Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>OUT_OF_RANGE", "Operand out of range, bitwise operation will lose information: {0}"); static final DiagnosticType SHIFT_AMOUNT_OUT_OF_BOUNDS = DiagnosticType.error( "JSC_SHIFT_AMOUNT_OUT_OF_BOUNDS", "Shift amount out of bounds: {0}"); static final DiagnosticType FRACTIONAL_BITWISE_OPERAND = DiagnosticType.error( "JSC_FRACTIONAL_BITWISE_OPERAND", "Fractional bitwise operand: {0}"); private static final double MAX_FOLD_NUMBER = Math.pow(2, 53); @Override Node optimizeSubtree(Node subtree) { switch(subtree.getType()) { case Token.CALL: return tryFoldKnownMethods(subtree); case Token.TYPEOF: return tryFoldTypeof(subtree); case Token.NOT: case Token.NEG: case Token.BITNOT: return tryFoldUnaryOperator(subtree); default: return tryFoldBinaryOperator(subtree); } } private Node tryFoldBinaryOperator(Node subtree) { Node left = subtree.getFirstChild(); if (left == null) { return subtree; } Node right = left.getNext(); if (right == null) { return subtree; } // If we've reached here, node is truly a binary operator. switch(subtree.getType()) { case Token.GETPROP: return tryFoldGetProp(subtree, left, right); case Token.GETELEM: return tryFoldGetElem(subtree, left, right); case Token.INSTANCEOF: return tryFoldInstanceof(subtree, left, right); case Token.AND: case Token.OR: return tryFoldAndOr(subtree, left, right); case Token.BITAND: case Token.BITOR: return tryFoldBitAndOr(subtree, left, right); case Token.LSH: case Token.RSH: case Token.URSH: return tryFoldShift(subtree, left, right); case Token.ASSIGN: return tryFoldAssign(subtree, left, right); case Token.ADD: return tryFoldAdd(subtree, left, right

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> */ @SuppressWarnings("fallthrough") private Node tryFoldComparison(Node n, Node left, Node right) { if (!NodeUtil.isLiteralValue(left) || !NodeUtil.isLiteralValue(right)) { // We only handle non-literal operands for LT and GT. if (n.getType() != Token.GT && n.getType() != Token.LT) { return n; } } int op = n.getType(); boolean result; // TODO(johnlenz): Use the JSType to compare nodes of different types. boolean rightLiteral = NodeUtil.isLiteralValue(right); boolean undefinedRight = ((Token.NAME == right.getType() && right.getString().equals("undefined")) || (Token.VOID == right.getType() && NodeUtil.isLiteralValue(right.getFirstChild()))); switch (left.getType()) { case Token.VOID: if (!NodeUtil.isLiteralValue(left.getFirstChild())) { return n; } else if (!rightLiteral) { return n; } else { boolean nullRight = (Token.NULL == right.getType()); boolean equivalent = undefinedRight || nullRight; switch (op) { case Token.EQ: // undefined is only equal to result = equivalent; break; case Token.NE: result = !equivalent; break; case Token.SHEQ: result = undefinedRight; break; case Token.SHNE: result = !undefinedRight; break; case Token.LT: case Token.GT: case Token.LE: case Token.GE: result = false; break; default: return n; } } break; case Token.NULL: if (undefinedRight) { result = (op == Token.EQ); break; } // fall through case Token.TRUE: case Token.FALSE: if (undefinedRight) { result = false; break; } // fall through case Token.THIS: int tt = right.getType(); if (tt != Token.THIS && tt != Token.TRUE && tt != Token.FALSE && tt != Token.NULL) { return n; } switch (op) { case

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> Id_export = Token.EXPORT, Id_false = Token.FALSE, Id_for = Token.FOR, Id_function = Token.FUNCTION, Id_if = Token.IF, Id_in = Token.IN, Id_new = Token.NEW, Id_null = Token.NULL, Id_return = Token.RETURN, Id_switch = Token.SWITCH, Id_this = Token.THIS, Id_true = Token.TRUE, Id_typeof = Token.TYPEOF, Id_var = Token.VAR, Id_void = Token.VOID, Id_while = Token.WHILE, Id_with = Token.WITH, // the following are #ifdef RESERVE_JAVA_KEYWORDS in jsscan.c Id_abstract = Token.RESERVED, Id_boolean = Token.RESERVED, Id_byte = Token.RESERVED, Id_catch = Token.CATCH, Id_char = Token.RESERVED, Id_class = Token.RESERVED, Id_const = Token.CONST, Id_debugger = Token.DEBUGGER, Id_double = Token.RESERVED, Id_enum = Token.RESERVED, Id_extends = Token.RESERVED, Id_final = Token.RESERVED, Id_finally = Token.FINALLY, Id_float = Token.RESERVED, Id_goto = Token.RESERVED, Id_implements = Token.RESERVED, Id_import = Token.IMPORT, Id_instanceof = Token.INSTANCEOF, Id_int = Token.RESERVED, Id_interface = Token.RESERVED, Id_long = Token.RESERVED, Id_native = Token.RESERVED, Id_package = Token.RESERVED, Id_private = Token.RESERVED, Id_protected = Token.RESERVED, Id_public = Token.RESERVED, Id_short = Token.RESERVED, Id_static = Token.RESERVED, Id_super = Token.RESERVED, Id_synchronized = Token.RESERVED, Id_throw = Token.THROW, Id_

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> or in case this SourceFile came // from a Jar, it could be the path to the Jar. private String originalPath = null; // Remember the offset for the previous line query. If the next line // is after this point, we can start scanning at the previous offset rather // than starting at the beginning of the file. private int lastOffset; private int lastLine; private String code = null; /** * Construct a new abstract source file. * * @param fileName The file name of the source file. It does not necessarily * need to correspond to a real path. But it should be unique. Will * appear in warning messages emitted by the compiler. */ SourceFile(String fileName) { this.fileName = fileName; // Starting point: offset 0 is at line 1. this.lastOffset = 0; this.lastLine = 1; } ////////////////////////////////////////////////////////////////////////////// // Implementation /** * Gets all the code in this source file. * @throws IOException */ public String getCode() throws IOException { return code; } /** * Gets a reader for the code in this source file. */ public Reader getCodeReader() throws IOException { return new StringReader(getCode()); } @VisibleForTesting String getCodeNoCache() { return code; } private void setCode(String sourceCode) { code = sourceCode; } public String getOriginalPath() { return originalPath != null ? originalPath : fileName; } public void setOriginalPath(String originalPath) { this.originalPath = originalPath; } // For SourceFile types which cache source code that can be regenerated // easily, flush the cache. We maintain the cache mostly to speed up // generating source when displaying error messages, so dumping the file // contents after the compile is a fine thing to do. public void clearCachedSource() { // By default, do nothing. Not all kinds of SourceFiles can regenerate // code. } boolean hasSourceInMemory() { return code != null; } /** Returns a unique name for the source file. */ public String getName() { return fileName; } /** * Gets the source line for the indicated line number. *

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> * @param lineNumber the line number, 1 being the first line of the file. * @return The line indicated. Does not include the newline at the end * of the file. Returns {@code null} if it does not exist, * or if there was an IO exception. */ public String getLine(int lineNumber) { String js = ""; try { // NOTE(nicksantos): Right now, this is optimized for few warnings. // This is probably the right trade-off, but will be slow if there // are lots of warnings in one file. js = getCode(); } catch (IOException e) { return null; } int pos = 0; int startLine = 1; // If we've saved a previous offset and it's for a line less than the // one we're searching for, then start at that point. if (lineNumber >= lastLine) { pos = lastOffset; startLine = lastLine; } for (int n = startLine; n < lineNumber; n++) { int nextpos = js.indexOf('\n', pos); if (nextpos == -1) { return null; } pos = nextpos + 1; } // Remember this offset for the next search we do. lastOffset = pos; lastLine = lineNumber; return (js.indexOf('\n', pos) == -1) ? null : js.substring(pos, js.indexOf('\n', pos)); } /** * Get a region around the indicated line number. The exact definition of a * region is implementation specific, but it must contain the line indicated * by the line number. A region must not start or end by a carriage return. * * @param lineNumber the line number, 1 being the first line of the file. * @return The line indicated. Returns {@code null} if it does not exist, * or if there was an IO exception. */ public Region getRegion(int lineNumber) { String js = ""; try { js = getCode(); } catch (IOException e) { return null; } int pos = 0; int startLine = Math.max(1, lineNumber - (SOURCE_EXCERPT_REGION_

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>LENGTH + 1) / 2 + 1); for (int n = 1; n < startLine; n++) { int nextpos = js.indexOf('\n', pos); if (nextpos == -1) { break; } pos = nextpos + 1; } int end = pos; int endLine = startLine; for (int n = 0; n < SOURCE_EXCERPT_REGION_LENGTH; n++, endLine++) { end = js.indexOf('\n', end); if (end == -1) { break; } end++; } if (lineNumber >= endLine) { return null; } if (end == -1) { int last = js.length() - 1; if (js.charAt(last) == '\n') { return new SimpleRegion(startLine, endLine, js.substring(pos, last)); } else { return new SimpleRegion(startLine, endLine, js.substring(pos)); } } else { return new SimpleRegion(startLine, endLine, js.substring(pos, end)); } } public static SourceFile fromFile(String fileName, Charset c) { return fromFile(new File(fileName), c); } public static SourceFile fromFile(String fileName) { return fromFile(new File(fileName)); } public static SourceFile fromFile(File file, Charset c) { return new OnDisk(file, c); } public static SourceFile fromFile(File file) { return new OnDisk(file); } public static SourceFile fromCode(String fileName, String code) { return new Preloaded(fileName, code); } public static SourceFile fromCode(String fileName, String originalPath, String code) { return new Preloaded(fileName, originalPath, code); } public static SourceFile fromInputStream(String fileName, InputStream s) throws IOException { return fromCode(fileName, CharStreams.toString(new InputStreamReader(s, Charsets.UTF_8))); } public static SourceFile fromInputStream(String fileName, String originalPath, InputStream s) throws IOException { return fromCode(fileName, originalPath, CharStreams.toString

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>(new InputStreamReader(s, Charsets.UTF_8))); } public static SourceFile fromReader(String fileName, Reader r) throws IOException { return fromCode(fileName, CharStreams.toString(r)); } public static SourceFile fromGenerator(String fileName, Generator generator) { return new Generated(fileName, generator); } ////////////////////////////////////////////////////////////////////////////// // Implementations /** * A source file where the code has been preloaded. */ static class Preloaded extends SourceFile { Preloaded(String fileName, String code) { this(fileName, fileName, code); } Preloaded(String fileName, String originalPath, String code) { super(fileName); super.setOriginalPath(originalPath); super.setCode(code); } } /** * A source file where the code will be dynamically generated * from the injected interface. */ static class Generated extends SourceFile { private final Generator generator; // Not private, so that LazyInput can extend it. Generated(String fileName, Generator generator) { super(fileName); this.generator = generator; } @Override public synchronized String getCode() throws IOException { String cachedCode = super.getCode(); if (cachedCode == null) { cachedCode = generator.getCode(); super.setCode(cachedCode); } return cachedCode; } // Clear out the generated code when finished with a compile; we can // regenerate it if we ever need it again. @Override public void clearCachedSource() { super.setCode(null); } } /** * A source file where the code is only read into memory if absolutely * necessary. We will try to delay loading the code into memory as long as * possible. */ static class OnDisk extends SourceFile { private final File file; // This is stored as a String, but passed in and out as a Charset so that // we can serialize the class. // Default input file format for JSCompiler has always been UTF_8. protected String inputCharset = Charsets.UTF_8.name(); OnDisk(File file, Charset c) { this(file); if (c != null) { this.setCharset(c); } } // No Charset provided?

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> OnDisk(File file) { super(file.getPath()); this.file = file; } @Override public synchronized String getCode() throws IOException { String cachedCode = super.getCode(); if (cachedCode == null) { cachedCode = Files.toString(file, this.getCharset()); super.setCode(cachedCode); } return cachedCode; } /** * Gets a reader for the code in this source file. */ @Override public Reader getCodeReader() throws IOException { if (hasSourceInMemory()) { return super.getCodeReader(); } else { // If we haven't pulled the code into memory yet, don't. return new FileReader(file); } } // Flush the cached code after the compile; we can read it off disk // if we need it again. @Override public void clearCachedSource() { super.setCode(null); } /** * Store the Charset specification as the string version of the name, * rather than the Charset itself. This allows us to serialize the * SourceFile class. * @param c charset to use when reading the input. */ public void setCharset(Charset c) { inputCharset = c.name(); } /** * Get the Charset specifying how we're supposed to read the file * in off disk and into UTF-16. This is stored as a strong to allow * SourceFile to be serialized. * @return Charset object representing charset to use. */ public Charset getCharset() { return Charset.forName(inputCharset); } } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> addVar(String name) { int vIndex = itsVariableNames.get(name, -1); if (vIndex != -1) { // There's already a variable or parameter with this name. if (vIndex >= varStart) { Object v = itsConst.get(vIndex); if (v != null) return DUPLICATE_CONST; else return DUPLICATE_VAR; } else return DUPLICATE_PARAMETER; } int index = itsVariables.size(); itsVariables.add(name); itsConst.add(null); itsVariableNames.put(name, index); return NO_DUPLICATE; } public final boolean addConst(String name) { int vIndex = itsVariableNames.get(name, -1); if (vIndex != -1) { // There's already a variable or parameter with this name. return false; } int index = itsVariables.size(); itsVariables.add(name); itsConst.add(name); itsVariableNames.put(name, index); return true; } public final void removeParamOrVar(String name) { int i = itsVariableNames.get(name, -1); if (i != -1) { itsVariables.remove(i); itsVariableNames.remove(name); ObjToIntMap.Iterator iter = itsVariableNames.newIterator(); for (iter.start(); !iter.done(); iter.next()) { int v = iter.getValue(); if (v > i) { iter.setValue(v - 1); } } } } public final Object getCompilerData() { return compilerData; } public final void setCompilerData(Object data) { if (data == null) throw new IllegalArgumentException(); // Can only call once if (compilerData != null) throw new IllegalStateException(); compilerData = data; } private int encodedSourceStart; private int encodedSourceEnd; private String sourceName; private int baseLineno = -1; private int endLineno = -1; private ObjArray functions; private ObjArray regexps; // a list of the formal parameters and local variables private ObjArray itsVariables

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>Mapping>() : null; } /** * Maintains a mapping from a given node to the position * in the source code at which its generated form was * placed. This position is relative only to the current * run of the CodeConsumer and will be normalized * later on by the SourceMap. * * @see SourceMap */ private static class Mapping { Node node; Position start; Position end; } /** * Starts the source mapping for the given * node at the current position. */ @Override void startSourceMapping(Node node) { if (createSrcMap && node.getProp(Node.SOURCEFILE_PROP) != null && node.getLineno() > 0) { int line = getCurrentLineIndex(); int index = getCurrentCharIndex(); // If the index is -1, we are not performing any mapping. if (index >= 0) { Mapping mapping = new Mapping(); mapping.node = node; mapping.start = new Position(line, index); mappings.push(mapping); allMappings.add(mapping); } } } /** * Finishes the source mapping for the given * node at the current position. */ @Override void endSourceMapping(Node node) { if (createSrcMap && node.getProp(Node.SOURCEFILE_PROP) != null && node.getLineno() > 0) { int line = getCurrentLineIndex(); int index = getCurrentCharIndex(); // If the index is -1, we are not performing any mapping. if (index >= 0) { Preconditions.checkState( !mappings.isEmpty(), "Mismatch in start and end of mapping"); Mapping mapping = mappings.pop(); mapping.end = new Position(line, index); } } } /** * Generates the source map from the given code consumer, * appending the information it saved to the SourceMap * object given. */ void generateSourceMap(SourceMap map){ if (createSrcMap) { for (Mapping mapping : allMappings) { map.addMapping(mapping.node, mapping.start, mapping.end); } } } /** * Reports to the code consumer that the given line

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> has been cut at the * given position (i.e. a \n has been inserted there). All mappings in * the source maps after that position will be renormalized as needed. */ void reportLineCut(int lineIndex, int charIndex) { if (createSrcMap) { for (Mapping mapping : allMappings) { mapping.start = convertPosition(mapping.start, lineIndex, charIndex); if (mapping.end != null) { mapping.end = convertPosition(mapping.end, lineIndex, charIndex); } } } } /** * Converts the given position by normalizing it against the insertion * of a newline at the given line and character position. * * @param position The existing position before the newline was inserted. * @param lineIndex The index of the line at which the newline was inserted. * @param characterPosition The position on the line at which the newline * was inserted. * * @return The normalized position. */ private Position convertPosition(Position position, int lineIndex, int characterPosition) { int originalLine = position.getLineNumber(); int originalChar = position.getCharacterIndex(); if (originalLine == lineIndex && originalChar >= characterPosition) { // If the position falls on the line itself, then normalize it // if it falls at or after the place the newline was inserted. return new Position(originalLine + 1, originalChar - characterPosition); } else { return position; } } public String getCode() { return code.toString(); } @Override char getLastChar() { return (code.length() > 0) ? code.charAt(code.length() - 1) : '\0'; } protected final int getCurrentCharIndex() { return lineLength; } protected final int getCurrentLineIndex() { return lineIndex; } } static class PrettyCodePrinter extends MappedCodePrinter { // The number of characters after which we insert a line break in the code static final String INDENT = " "; private int indent = 0; /** * @param lineLengthThreshold The length of a line after which we force * a newline when possible. */ private PrettyCodePrinter( int

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> lineLengthThreshold, boolean createSourceMap) { super(lineLengthThreshold, createSourceMap); } /** * Appends a string to the code, keeping track of the current line length. */ @Override void append(String str) { // For pretty printing: indent at the beginning of the line if (lineLength == 0) { for (int i = 0; i < indent; i++) { code.append(INDENT); lineLength += INDENT.length(); } } code.append(str); lineLength += str.length(); } /** * Adds a newline to the code, resetting the line length and handling * indenting for pretty printing. */ @Override void startNewLine() { if (lineLength > 0) { code.append('\n'); lineIndex++; lineLength = 0; } } @Override void maybeLineBreak() { maybeCutLine(); } /** * This may start a new line if the current line is longer than the line * length threshold. */ @Override void maybeCutLine() { if (lineLength > lineLengthThreshold) { startNewLine(); } } @Override void endLine() { startNewLine(); } @Override void appendBlockStart() { append(" {"); indent++; } @Override void appendBlockEnd() { endLine(); indent--; append("}"); } @Override void listSeparator() { add(", "); maybeLineBreak(); } @Override void endFunction(boolean statementContext) { super.endFunction(statementContext); if (statementContext) { startNewLine(); } } @Override void beginCaseBody() { super.beginCaseBody(); indent++; endLine(); } @Override void endCaseBody() { super.endCaseBody(); indent--; endStatement(); } @Override void appendOp(String op, boolean binOp) { if (binOp) { if (getLastChar() != ' ') { append(" "); } append(op); append(" "); } else { append(op); } } /** * If the body

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> of a for loop or the then clause of an if statement has * a single statement, should it be wrapped in a block? * {@inheritDoc} */ @Override boolean shouldPreserveExtraBlocks() { // When pretty-printing, always place the statement in its own block // so it is printed on a separate line. This allows breakpoints to be // placed on the statement. return true; } /** * @return The TRY node for the specified CATCH node. */ private Node getTryForCatch(Node n) { return n.getParent().getParent(); } /** * @return Whether the a line break should be added after the specified * BLOCK. */ @Override boolean breakAfterBlockFor(Node n, boolean isStatementContext) { Preconditions.checkState(n.getType() == Token.BLOCK); Node parent = n.getParent(); if (parent != null) { int type = parent.getType(); switch (type) { case Token.DO: // Don't break before 'while' in DO-WHILE statements. return false; case Token.FUNCTION: // FUNCTIONs are handled separately, don't break here. return false; case Token.TRY: // Don't break before catch return n != parent.getFirstChild(); case Token.CATCH: // Don't break before finally return !NodeUtil.hasFinally(getTryForCatch(parent)); case Token.IF: // Don't break before else return n == parent.getLastChild(); } } return true; } } static class CompactCodePrinter extends MappedCodePrinter { // The CompactCodePrinter tries to emit just enough newlines to stop there // being lines longer than the threshold. Since the output is going to be // gzipped, it makes sense to try to make the newlines appear in similar // contexts so that GZIP can encode them for 'free'. // // This version tries to break the lines at 'preferred' places, which are // between the top-level forms. This works because top level forms tend to // be more uniform than arbitary legal contexts. Better compression would // probably require explicit modelling of the gzip algorithm. private final boolean lineBreak; private int line

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>StartPosition = 0; private int preferredBreakPosition = 0; /** * @param lineBreak break the lines a bit more aggressively * @param lineLengthThreshold The length of a line after which we force * a newline when possible. * @param createSrcMap Whether to gather source position * mapping information when printing. */ private CompactCodePrinter(boolean lineBreak, int lineLengthThreshold, boolean createSrcMap) { super(lineLengthThreshold, createSrcMap); this.lineBreak = lineBreak; } /** * Appends a string to the code, keeping track of the current line length. */ @Override void append(String str) { code.append(str); lineLength += str.length(); } /** * Adds a newline to the code, resetting the line length. */ @Override void startNewLine() { if (lineLength > 0) { code.append('\n'); lineLength = 0; lineIndex++; lineStartPosition = code.length(); } } @Override void maybeLineBreak() { if (lineBreak) { if (sawFunction) { startNewLine(); sawFunction = false; } } // Since we are at a legal line break, can we upgrade the // preferred break position? We prefer to break after a // semicolon rather than before it. int len = code.length(); if (preferredBreakPosition == len - 1) { char ch = code.charAt(len - 1); if (ch == ';') { preferredBreakPosition = len; } } maybeCutLine(); } /** * This may start a new line if the current line is longer than the line * length threshold. */ @Override void maybeCutLine() { if (lineLength > lineLengthThreshold) { // Use the preferred position provided it will break the line. if (preferredBreakPosition > lineStartPosition && preferredBreakPosition < lineStartPosition + lineLength) { int position = preferredBreakPosition; code.insert(position, '\n'); reportLineCut(lineIndex, position - lineStartPosition); lineIndex++; lineLength -= (position - lineStartPosition

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>); lineStartPosition = position + 1; } else { startNewLine(); } } } @Override void notePreferredLineBreak() { preferredBreakPosition = code.length(); } } static class Builder { private final Node root; private boolean prettyPrint = false; private boolean lineBreak = false; private boolean outputTypes = false; private int lineLengthThreshold = DEFAULT_LINE_LENGTH_THRESHOLD; private SourceMap sourceMap = null; // Specify a charset to use when outputting source code. If null, // then just output ASCII. private Charset outputCharset = null; /** * Sets the root node from which to generate the source code. * @param node The root node. */ Builder(Node node) { root = node; } /** * Sets whether pretty printing should be used. * @param prettyPrint If true, pretty printing will be used. */ Builder setPrettyPrint(boolean prettyPrint) { this.prettyPrint = prettyPrint; return this; } /** * Sets whether line breaking should be done automatically. * @param lineBreak If true, line breaking is done automatically. */ Builder setLineBreak(boolean lineBreak) { this.lineBreak = lineBreak; return this; } /** * Sets whether to output closure-style type annotations. * @param outputTypes If true, outputs closure-style type annotations. */ Builder setOutputTypes(boolean outputTypes) { this.outputTypes = outputTypes; return this; } /** * Sets the line length threshold that will be used to determine * when to break lines, if line breaking is on. * * @param threshold The line length threshold. */ Builder setLineLengthThreshold(int threshold) { this.lineLengthThreshold = threshold; return this; } /** * Sets the source map to which to write the metadata about * the generated source code. * * @param sourceMap The source map. */ Builder setSourceMap(SourceMap sourceMap) { this.sourceMap = sourceMap; return this; } /** * Set the charset to use when determining what characters need to be * escaped in the output. */ Builder set

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> } private FlowScope caseNameOrGetProp(Node name, FlowScope blindScope, boolean outcome) { JSType type = getTypeIfRefinable(name, blindScope); if (type != null) { JSType restrictedType = type.getRestrictedTypeGivenToBooleanOutcome(outcome); FlowScope informed = blindScope.createChildFlowScope(); declareNameInScope(informed, name, restrictedType); return informed; } return blindScope; } private FlowScope caseTypeOf(Node node, JSType type, String value, boolean resultEqualsValue, FlowScope blindScope) { JSType restrictedType = getRestrictedByTypeOfResult(type, value, resultEqualsValue); if (restrictedType == null) { return blindScope; } FlowScope informed = blindScope.createChildFlowScope(); declareNameInScope(informed, node, restrictedType); return informed; } private FlowScope caseInstanceOf(Node left, Node right, FlowScope blindScope, boolean outcome) { JSType leftType = getTypeIfRefinable(left, blindScope); if (leftType == null) { return blindScope; } JSType rightType = right.getJSType(); ObjectType targetType = typeRegistry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE); if (rightType instanceof FunctionType) { targetType = (FunctionType) rightType; } Visitor<JSType> visitor; if (outcome) { visitor = new RestrictByTrueInstanceOfResultVisitor(targetType); } else { visitor = new RestrictByFalseInstanceOfResultVisitor(targetType); } JSType restrictedLeftType = leftType.visit(visitor); if (restrictedLeftType != null && !restrictedLeftType.equals(leftType)) { FlowScope informed = blindScope.createChildFlowScope(); declareNameInScope(informed, left, restrictedLeftType); return informed; } return blindScope; } /** * Given 'property in object', ensures that the object has the property in the * informed scope by defining it as a qualified name if the object type lacks * the property and it's not in the blind scope. * @param object The node of the right-

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>side of the in. * @param propertyName The string of the left-side of the in. */ private FlowScope caseIn(Node object, String propertyName, FlowScope blindScope) { JSType jsType = object.getJSType(); jsType = this.getRestrictedWithoutNull(jsType); jsType = this.getRestrictedWithoutUndefined(jsType); boolean hasProperty = false; ObjectType objectType = ObjectType.cast(jsType); if (objectType != null) { hasProperty = objectType.hasProperty(propertyName); } if (!hasProperty) { String qualifiedName = object.getQualifiedName(); if (qualifiedName != null) { String propertyQualifiedName = qualifiedName + "." + propertyName; if (blindScope.getSlot(propertyQualifiedName) == null) { FlowScope informed = blindScope.createChildFlowScope(); JSType unknownType = typeRegistry.getNativeType( JSTypeNative.UNKNOWN_TYPE); informed.inferQualifiedSlot( propertyQualifiedName, unknownType, unknownType); return informed; } } } return blindScope; } /** * @see SemanticReverseAbstractInterpreter#caseInstanceOf */ private class RestrictByTrueInstanceOfResultVisitor extends RestrictByTrueTypeOfResultVisitor { private final ObjectType target; RestrictByTrueInstanceOfResultVisitor(ObjectType target) { this.target = target; } @Override protected JSType caseTopType(JSType type) { return applyCommonRestriction(type); } @Override public JSType caseUnknownType() { if (target instanceof FunctionType) { FunctionType funcTarget = (FunctionType) target; if (funcTarget.hasInstanceType()) { return funcTarget.getInstanceType(); } } return getNativeType(UNKNOWN_TYPE); } @Override public JSType caseObjectType(ObjectType type) { return applyCommonRestriction(type); } @Override public JSType caseUnionType(UnionType type) { return applyCommonRestriction(type); } @Override public JSType caseFunctionType(FunctionType type) { return caseObjectType(type); } private JSType applyCommonRestriction(JSType type) { if (target.isUnknownType()) { return type; }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> FunctionType funcTarget = (FunctionType) target; if (funcTarget.hasInstanceType()) { return type.getGreatestSubtype(funcTarget.getInstanceType()); } return null; } } /** * @see SemanticReverseAbstractInterpreter#caseInstanceOf */ private class RestrictByFalseInstanceOfResultVisitor extends RestrictByFalseTypeOfResultVisitor { private final ObjectType target; RestrictByFalseInstanceOfResultVisitor(ObjectType target) { this.target = target; } @Override public JSType caseObjectType(ObjectType type) { if (target.isUnknownType()) { return type; } FunctionType funcTarget = (FunctionType) target; if (funcTarget.hasInstanceType()) { if (type.isSubtype(funcTarget.getInstanceType())) { return null; } return type; } return null; } @Override public JSType caseUnionType(UnionType type) { if (target.isUnknownType()) { return type; } FunctionType funcTarget = (FunctionType) target; if (funcTarget.hasInstanceType()) { return type.getRestrictedUnion(funcTarget.getInstanceType()); } return null; } @Override public JSType caseFunctionType(FunctionType type) { return caseObjectType(type); } } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>/* * Copyright 2007 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.javascript.rhino.Node; import java.util.regex.Pattern; /** * This describes the Google-specific JavaScript coding conventions. * Within Google, variable names are semantically significant. * * */ public class GoogleCodingConvention extends ClosureCodingConvention { private static final String OPTIONAL_ARG_PREFIX = "opt_"; private static final String VAR_ARGS_NAME = "var_args"; private static final Pattern ENUM_KEY_PATTERN = Pattern.compile("[A-Z0-9][A-Z0-9_]*"); /** * {@inheritDoc} * * <p>This enforces the Google const name convention, that the first character * after the last $ must be an upper-case letter and all subsequent letters * must be upper case. The name must be at least 2 characters long. * * <p>Examples: * <pre> * aaa Not constant - lower-case letters in the name * A Not constant - too short * goog$A Constant - letters after the $ are upper-case. * AA17 Constant - digits can appear after the first letter * goog$7A Not constant - first character after the $ must be * upper case. * $A Constant - doesn't have to be anything in front of the $ * </pre> */ @Override public boolean isConstant(String name) { if (name.length() <= 1) { return false; } // In compiled

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> code, '$' is often a namespace delimiter. To allow inlining // of namespaced constants, we strip off any namespaces here. int pos = name.lastIndexOf('$'); if (pos >= 0) { name = name.substring(pos + 1); if (name.length() == 0) { return false; } } return isConstantKey(name); } @Override public boolean isConstantKey(String name) { if (name.isEmpty() || !Character.isUpperCase(name.charAt(0))) { return false; } // hack way of checking that there aren't any lower-case letters return name.toUpperCase().equals(name); } /** * {@inheritDoc} * * <p>This enforces Google's convention about enum key names. They must match * the regular expression {@code [A-Z0-9][A-Z0-9_]*}. * * <p>Examples: * <ul> * <li>A</li> * <li>213</li> * <li>FOO_BAR</li> * </ul> */ @Override public boolean isValidEnumKey(String key) { return ENUM_KEY_PATTERN.matcher(key).matches(); } /** * {@inheritDoc} * * <p>In Google code, parameter names beginning with {@code opt_} are * treated as optional arguments. */ @Override public boolean isOptionalParameter(Node parameter) { return parameter.getString().startsWith(OPTIONAL_ARG_PREFIX); } @Override public boolean isVarArgsParameter(Node parameter) { return VAR_ARGS_NAME.equals(parameter.getString()); } /** * {@inheritDoc} * * <p>In Google code, any global name starting with an underscore is * considered exported. */ @Override public boolean isExported(String name, boolean local) { return !local && name.startsWith("_"); } /** * {@inheritDoc} * * <p>In Google code, private names end with an underscore, and exported * names are never considered private (see {@link #isExported}). */ @Override public boolean isPrivate(String name) { return name

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>); } } private boolean hasHaltingErrors() { return compiler.hasHaltingErrors(); } /** * Returns a new tracer for the given pass name. */ private Tracer newTracer(String passName) { String comment = passName + (recentChange.hasCodeChanged() ? " on recently changed AST" : ""); if (tracker != null) { tracker.recordPassStart(passName); } return new Tracer("JSCompiler", comment); } private void stopTracer(Tracer t, String passName) { long result = t.stop(); if (tracker != null) { tracker.recordPassStop(passName, result); } } /** * A single compiler pass. */ private abstract class NamedPass implements CompilerPass { private final String name; NamedPass(String name) { this.name = name; } public void process(Node externs, Node root) { logger.info(name); startPass(name); processInternal(externs, root); endPass(externs, root); } abstract void processInternal(Node externs, Node root); } /** * Delegates to a PassFactory for processing. */ private class PassFactoryDelegate extends NamedPass { private final AbstractCompiler myCompiler; private final PassFactory factory; private PassFactoryDelegate( AbstractCompiler myCompiler, PassFactory factory) { super(factory.getName()); this.myCompiler = myCompiler; this.factory = factory; } @Override void processInternal(Node externs, Node root) { factory.create(myCompiler).process(externs, root); } } /** * Runs a set of compiler passes until they reach a fixed point. */ static abstract class Loop implements CompilerPass { abstract void addLoopedPass(PassFactory factory); } /** * Runs a set of compiler passes until they reach a fixed point. * * Notice that this is a non-static class, because it includes the closure * of PhaseOptimizer. */ private class LoopInternal extends Loop { private final List<NamedPass> myPasses = Lists.newArrayList(); private final Set<String> myNames = Sets.newHashSet(); @Override void

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>/* * Copyright 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.javascript.rhino.JSDocInfo; import com.google.javascript.rhino.JSTypeExpression; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; /** * Prepare the AST before we do any checks or optimizations on it. * * This pass must run. It should bring the AST into a consistent state, * and add annotations where necessary. It should not make any transformations * on the tree that would lose source information, since we need that source * information for checks. * * @author johnlenz@google.com (John Lenz) */ class PrepareAst implements CompilerPass { private final AbstractCompiler compiler; private final boolean checkOnly; PrepareAst(AbstractCompiler compiler) { this(compiler, false); } PrepareAst(AbstractCompiler compiler, boolean checkOnly) { this.compiler = compiler; this.checkOnly = checkOnly; } private void reportChange() { if (checkOnly) { Preconditions.checkState(false, "normalizeNodeType constraints violated"); } } @Override public void process(Node externs, Node root) { if (checkOnly) { normalizeNodeTypes(root); } else { // Don't perform "PrepareAnnoations" when doing checks as // they currently aren't valid during sanity checks. In particular, // they DIRECT_EVAL shouldn't be applied after inlining has been // performed. if (extern

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>s != null) { NodeTraversal.traverse( compiler, externs, new PrepareAnnotations(compiler)); } if (root != null) { NodeTraversal.traverse( compiler, root, new PrepareAnnotations(compiler)); } } } /** * Covert EXPR_VOID to EXPR_RESULT to simplify the rest of the code. */ private void normalizeNodeTypes(Node n) { if (n.getType() == Token.EXPR_VOID) { n.setType(Token.EXPR_RESULT); reportChange(); } // Remove unused properties to minimize differences between ASTs // produced by the two parsers. if (n.getType() == Token.FUNCTION) { Preconditions.checkState(n.getProp(Node.FUNCTION_PROP) == null); } normalizeBlocks(n); for (Node child = n.getFirstChild(); child != null; child = child.getNext()) { // This pass is run during the CompilerTestCase validation, so this // parent pointer check serves as a more general check. Preconditions.checkState(child.getParent() == n); normalizeNodeTypes(child); } } /** * Add blocks to IF, WHILE, DO, etc. */ private void normalizeBlocks(Node n) { if (NodeUtil.isControlStructure(n) && n.getType() != Token.LABEL && n.getType() != Token.SWITCH) { for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (NodeUtil.isControlStructureCodeBlock(n,c) && c.getType() != Token.BLOCK) { Node newBlock = new Node(Token.BLOCK, n.getLineno(), n.getCharno()); newBlock.copyInformationFrom(n); n.replaceChild(c, newBlock); if (c.getType() != Token.EMPTY) { newBlock.addChildrenToFront(c); } else { newBlock.setWasEmptyNode(true); } c = newBlock; reportChange(); } } } } /** * Normalize where annotations appear on the AST. Copies * around existing JSDoc annotations as well as internal annotations. */ static class PrepareAnnotations

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> extends NodeTraversal.AbstractPostOrderCallback { private final CodingConvention convention; PrepareAnnotations(AbstractCompiler compiler) { this.convention = compiler.getCodingConvention(); } /** * * In the AST that Rhino gives us, it needs to make a distinction * between jsdoc on the object literal node and jsdoc on the object literal * value. For example, * <pre> * var x = { * / JSDOC / * a: 'b', * c: / JSDOC / 'd' * }; * </pre> * * But in few narrow cases (in particular, function literals), it's * a lot easier for us if the doc is attached to the value. */ @SuppressWarnings("fallthrough") public void visit(NodeTraversal t, Node n, Node parent) { int nType = n.getType(); switch (nType) { case Token.STRING: // There are only two cases where a string token // may be a variable reference: The right side of a GETPROP // or an OBJECTLIT key. if (parent.getType() != Token.OBJECTLIT && parent.getType() != Token.GETPROP) { break; } // fall-through case Token.NAME: String nString = n.getString(); if (nType == Token.NAME && n.getParent().getType() == Token.CALL && "eval".equals(nString)) { n.putBooleanProp(Node.DIRECT_EVAL, true); } if (NodeUtil.isConstantByConvention(convention, n, parent)) { n.putBooleanProp(Node.IS_CONSTANT_NAME, true); } break; case Token.FUNCTION: JSDocInfo fnInfo = n.getJSDocInfo(); if (fnInfo == null) { // Look for the info on other nodes. if (parent.getType() == Token.ASSIGN) { // on ASSIGNs fnInfo = parent.getJSDocInfo(); } else if (parent.getType() == Token.NAME) { // on var NAME = function() { ... }; fnInfo = parent.getParent().getJSDocInfo(); } } // Compute which function parameters are

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> the JSType from the Node argument and verifies that it is * present. */ private JSType getJSType(Node n) { JSType jsType = n.getJSType(); if (jsType == null) { // TODO(user): This branch indicates a compiler bug, not worthy of // halting the compilation but we should log this and analyze to track // down why it happens. This is not critical and will be resolved over // time as the type checker is extended. return getNativeType(UNKNOWN_TYPE); } else { return jsType; } } private JSType getNativeType(JSTypeNative typeId) { return typeRegistry.getNativeType(typeId); } /** * Signals that the first type and the second type have been * used interchangeably. * * Type-based optimizations should take this into account * so that they don't wreck code with type warnings. */ static class TypeMismatch { final JSType typeA; final JSType typeB; /** * It's the responsibility of the class that creates the * {@code TypeMismatch} to ensure that {@code a} and {@code b} are * non-matching types. */ TypeMismatch(JSType a, JSType b) { this.typeA = a; this.typeB = b; } @Override public boolean equals(Object object) { if (object instanceof TypeMismatch) { TypeMismatch that = (TypeMismatch) object; return (that.typeA.equals(this.typeA) && that.typeB.equals(this.typeB)) || (that.typeB.equals(this.typeA) && that.typeA.equals(this.typeB)); } return false; } @Override public int hashCode() { return Objects.hashCode(typeA, typeB); } @Override public String toString() { return "(" + typeA + ", " + typeB + ")"; } } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>registry, registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE)); this.name = name; } @Override public String getReferenceName() { return name; } @Override public String toString() { return name; } @Override public boolean isTemplateType() { return true; } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>Format); } /** * Create a DiagnosticType at a given CheckLevel. * * @param name An identifier * @param level Either CheckLevel.ERROR or CheckLevel.WARNING * @param descriptionFormat A format string * @return A new DiagnosticType */ public static DiagnosticType make(String name, CheckLevel level, String descriptionFormat) { return new DiagnosticType(name, level, new MessageFormat(descriptionFormat)); } /** * Create a DiagnosticType. Private to force use of static factory methods. */ private DiagnosticType(String key, CheckLevel level, MessageFormat format) { this.key = key; this.defaultLevel = level; this.format = format; this.level = this.defaultLevel; } /** * Create a description from the MessageFormat and the arguments. * Used by unit tests. */ String format(Object ... arguments) { return format.format(arguments); } @Override public int compareTo(DiagnosticType diagnosticType) { return key.compareTo(diagnosticType.key); } @Override public String toString() { return key + ": " + format.toPattern(); } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import static com.google.javascript.rhino.jstype.TernaryValue.FALSE; import static com.google.javascript.rhino.jstype.TernaryValue.UNKNOWN; /** * Boolean type. * */ public class BooleanType extends ValueType { private static final long serialVersionUID = 1L; BooleanType(JSTypeRegistry registry) { super(registry); } @

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>Override public boolean isNullable() { return false; } @Override public TernaryValue testForEquality(JSType that) { if (UNKNOWN.equals(super.testForEquality(that))) { return UNKNOWN; } if (that.isUnknownType() || that.isSubtype( getNativeType(JSTypeNative.NUMBER_STRING_BOOLEAN)) || that.isObject()) { return UNKNOWN; } return FALSE; } @Override public boolean isBooleanValueType() { return true; } @Override public boolean matchesNumberContext() { return true; } @Override public boolean matchesStringContext() { return true; } @Override public boolean matchesObjectContext() { // TODO(user): Revisit this for ES4, which is stricter. return true; } @Override public JSType autoboxesTo() { return getNativeType(JSTypeNative.BOOLEAN_OBJECT_TYPE); } @Override public String toString() { return "boolean"; } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.BOTH; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseBooleanType(); } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>(); for (Name name : namespace.getNameIndex().values()) { if (name.docInfo != null && name.docInfo.isDefine()) { // Process defines should not depend on check types being enabled, // so we look for the JSDoc instead of the inferred type. if (isValidDefineType(name.docInfo.getType())) { allDefines.add(name); } else { JSError error = JSError.make( name.declaration.sourceName, name.declaration.node, INVALID_DEFINE_TYPE_ERROR); compiler.report(error); } } else if (name.refs != null) { for (Ref ref : name.refs) { Node n = ref.node; Node parent = ref.node.getParent(); JSDocInfo info = n.getJSDocInfo(); if (info == null && parent.getType() == Token.VAR && parent.hasOneChild()) { info = parent.getJSDocInfo(); } if (info != null && info.isDefine()) { allDefines.add(name); break; } } } } CollectDefines pass = new CollectDefines(compiler, allDefines); NodeTraversal.traverse(compiler, root, pass); return pass.getAllDefines(); } /** * Finds all assignments to @defines, and figures out the last value of * the @define. */ private static final class CollectDefines implements Callback { private final AbstractCompiler compiler; private final Map<String, DefineInfo> assignableDefines; private final Map<String, DefineInfo> allDefines; private final Map<Node, RefInfo> allRefInfo; // A hack that allows us to remove ASSIGN/VAR statements when // we're currently visiting one of the children of the assign. private Node lvalueToRemoveLater = null; // A stack tied to the node traversal, to keep track of whether // we're in a conditional block. If 1 is at the top, assignment to // a define is allowed. Otherwise, it's not allowed. private final Deque<Integer> assignAllowed; CollectDefines(AbstractCompiler compiler, List<Name> listOfDefines) { this.compiler = compiler; this.allDefines = Maps.newHashMap();

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> assignableDefines = Maps.newHashMap(); assignAllowed = new ArrayDeque<Integer>(); assignAllowed.push(1); // Create a map of references to defines keyed by node for easy lookup allRefInfo = Maps.newHashMap(); for (Name name : listOfDefines) { if (name.declaration != null) { allRefInfo.put(name.declaration.node, new RefInfo(name.declaration, name)); } if (name.refs != null) { for (Ref ref : name.refs) { // If there's a TWIN def, only put one of the twins in. if (ref.getTwin() == null || !ref.getTwin().isSet()) { allRefInfo.put(ref.node, new RefInfo(ref, name)); } } } } } /** * Get a map of {@link DefineInfo} structures, keyed by the name of * the define. */ Map<String, DefineInfo> getAllDefines() { return allDefines; } /** * Keeps track of whether the traversal is in a conditional branch. * We traverse all nodes of the parse tree. */ public boolean shouldTraverse(NodeTraversal nodeTraversal, Node n, Node parent) { updateAssignAllowedStack(n, true); return true; } public void visit(NodeTraversal t, Node n, Node parent) { RefInfo refInfo = allRefInfo.get(n); if (refInfo != null) { Ref ref = refInfo.ref; Name name = refInfo.name; String fullName = name.fullName(); switch (ref.type) { case SET_FROM_GLOBAL: case SET_FROM_LOCAL: Node valParent = getValueParent(ref); Node val = valParent.getLastChild(); if (valParent.getType() == Token.ASSIGN && name.isSimpleName() && name.declaration == ref) { // For defines, it's an error if a simple name is assigned // before it's declared compiler.report( t.makeError(val, INVALID_DEFINE_INIT_ERROR, fullName)); } else if (processDefineAssignment(t, fullName, val, valParent)) { // remove the assignment so that the

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>} until requested by * {@link #getControlFlowGraph()}. Note that {@link ArrayDeque} does not allow * {@code null} elements, so {@link LinkedList} is used instead. */ Deque<ControlFlowGraph<Node>> cfgs = new LinkedList<ControlFlowGraph<Node>>(); /** The current source file name */ private String sourceName; /** The scope creator */ private ScopeCreator scopeCreator; /** Possible callback for scope entry and exist **/ private ScopedCallback scopeCallback; /** * Callback */ public interface Callback { /** * <p>Visits a node in pre order (before visiting its children) and decides * whether this node's children should be traversed. If children are * traversed, they will be visited by * {@link #visit(NodeTraversal, Node, Node)} in post order.</p> * <p>Implementations can have side effects (e.g. modifying the parse * tree).</p> * @return whether the children of this node should be visited */ boolean shouldTraverse(NodeTraversal nodeTraversal, Node n, Node parent); /** * <p>Visits a node in post order (after its children have been visited). * A node is visited only if all its parents should be traversed * ({@link #shouldTraverse(NodeTraversal, Node, Node)}).</p> * <p>Implementations can have side effects (e.g. modifying the parse * tree).</p> */ void visit(NodeTraversal t, Node n, Node parent); } /** * Callback that also knows about scope changes */ public interface ScopedCallback extends Callback { /** * Called immediately after entering a new scope. The new scope can * be accessed through t.getScope() */ void enterScope(NodeTraversal t); /** * Called immediately before exiting a scope. The ending scope can * be accessed through t.getScope() */ void exitScope(NodeTraversal t); } /** * Abstract callback to visit all nodes in post order. * */ public abstract static class AbstractPostOrderCallback implements Callback { public final boolean shouldTraverse(NodeTraversal nodeTraversal, Node n, Node parent) { return true; } } /** * Abstract callback to

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> if (cb instanceof ScopedCallback) { this.scopeCallback = (ScopedCallback) cb; } this.compiler = compiler; this.sourceName = ""; this.scopeCreator = scopeCreator; } private void throwUnexpectedException(Exception unexpectedException) { // If there's an unexpected exception, try to get the // line number of the code that caused it. String message = unexpectedException.getMessage(); // TODO(user): It is possible to get more information if curNode or // its parent is missing. We still have the scope stack in which it is still // very useful to find out at least which function caused the exception. if (!sourceName.isEmpty()) { message = unexpectedException.getMessage() + "\n" + formatNodeContext("Node", curNode) + (curNode == null ? "" : formatNodeContext("Parent", curNode.getParent())); } compiler.throwInternalError(message, unexpectedException); } private String formatNodeContext(String label, Node n) { if (n == null) { return " " + label + ": NULL"; } return " " + label + "(" + n.toString(false, false, false) + "): " + formatNodePosition(n); } /** * Traverses a parse tree recursively. */ public void traverse(Node root) { try { sourceName = ""; curNode = root; pushScope(root); traverseBranch(root, null); popScope(); } catch (Exception unexpectedException) { throwUnexpectedException(unexpectedException); } } public void traverseRoots(Node ... roots) { traverseRoots(Lists.newArrayList(roots)); } public void traverseRoots(List<Node> roots) { if (roots.isEmpty()) { return; } try { Node scopeRoot = roots.get(0).getParent(); Preconditions.checkState(scopeRoot != null); sourceName = ""; curNode = scopeRoot; pushScope(scopeRoot); for (Node root : roots) { Preconditions.checkState(root.getParent() == scopeRoot); traverseBranch(root, scopeRoot); } popScope(); } catch (Exception unexpectedException) { throwUnexpectedException(unexpectedException

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>code null} */ protected void traverseInnerNode(Node node, Node parent, Scope refinedScope) { Preconditions.checkNotNull(parent); if (refinedScope != null && getScope() != refinedScope) { curNode = node; pushScope(refinedScope); traverseBranch(node, parent); popScope(); } else { traverseBranch(node, parent); } } /** * Gets the compiler. */ public Compiler getCompiler() { // TODO(nicksantos): Remove this type cast. This is just temporary // while refactoring. return (Compiler) compiler; } /** * Gets the current line number, or zero if it cannot be determined. The line * number is retrieved lazily as a running time optimization. */ public int getLineNumber() { Node cur = curNode; while (cur != null) { int line = cur.getLineno(); if (line >=0) { return line; } cur = cur.getParent(); } return 0; } /** * Gets the current input source name. * * @return A string that may be empty, but not null */ public String getSourceName() { return sourceName; } /** * Gets the current input source. */ public CompilerInput getInput() { return compiler.getInput(sourceName); } /** * Gets the current input module. */ public JSModule getModule() { CompilerInput input = getInput(); return input == null ? null : input.getModule(); } /** Returns the node currently being traversed. */ public Node getCurrentNode() { return curNode; } /** * Traverses a node recursively. */ public static void traverse( AbstractCompiler compiler, Node root, Callback cb) { NodeTraversal t = new NodeTraversal(compiler, cb); t.traverse(root); } /** * Traverses a list of node trees. */ public static void traverseRoots( AbstractCompiler compiler, List<Node> roots, Callback cb) { NodeTraversal t = new NodeTraversal(compiler, cb); t.traverseRoots(roots); } /** * Traverses a branch. */ @SuppressWarnings("

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>fallthrough") private void traverseBranch(Node n, Node parent) { int type = n.getType(); if (type == Token.SCRIPT) { sourceName = getSourceName(n); } curNode = n; if (!callback.shouldTraverse(this, n, parent)) return; switch (type) { case Token.CATCH: Preconditions.checkState(n.getChildCount() == 3); Preconditions.checkState(n.getFirstChild().getType() == Token.NAME); // the first child is the catch var and the third child // is the code block traverseBranch(n.getFirstChild(), n); traverseBranch(n.getFirstChild().getNext().getNext(), n); break; case Token.FUNCTION: traverseFunction(n, parent); break; default: for (Node child = n.getFirstChild(); child != null; ) { // child could be replaced, in which case our child node // would no longer point to the true next Node next = child.getNext(); traverseBranch(child, n); child = next; } break; } curNode = n; callback.visit(this, n, parent); } /** * Traverses a function. */ private void traverseFunction(Node n, Node parent) { Preconditions.checkState(n.getChildCount() == 3); Preconditions.checkState(n.getType() == Token.FUNCTION); final Node fnName = n.getFirstChild(); boolean isFunctionExpression = (parent != null) && NodeUtil.isFunctionExpression(n); if (!isFunctionExpression) { // Functions declarations are in the scope containing the declaration. traverseBranch(fnName, n); } curNode = n; pushScope(n); if (isFunctionExpression) { // Function expression names are only accessible within the function // scope. traverseBranch(fnName, n); } final Node args = fnName.getNext(); final Node body = args.getNext(); // Args traverseBranch(args, n); // Body Preconditions.checkState(body.getNext() == null && body.getType() == Token.BLOCK); traverseBranch(body, n); popScope(); } /** Examines the functions stack for

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>provide/goog.require calls, and prune inputs * whose symbols are not required. */ public void setManageClosureDependencies(boolean newVal) { manageClosureDependencies = newVal; } /** * Controls how detailed the compilation summary is. Values: * 0 (never print summary), 1 (print summary only if there are * errors or warnings), 2 (print summary if type checking is on, * see --check_types), 3 (always print summary). The default level * is 1 */ public void setSummaryDetailLevel(int summaryDetailLevel) { this.summaryDetailLevel = summaryDetailLevel; } public void enableExternExports(boolean enable) { this.externExports = enable; } public boolean isExternExportsEnabled() { return externExports; } /** * Whether to include "undefined" in the default types. * For example: * "{Object}" is normally "Object|null" becomes "Object|null|undefined" * "{?string}" is normally "string|null" becomes "string|null|undefined" * In either case "!" annotated types excluded both null and undefined. */ public void setLooseTypes(boolean looseTypes) { this.looseTypes = looseTypes; } @Override public Object clone() throws CloneNotSupportedException { CompilerOptions clone = (CompilerOptions) super.clone(); // TODO(bolinfest): Add relevant custom cloning. return clone; } ////////////////////////////////////////////////////////////////////////////// // Enums /** When to do the extra sanity checks */ static enum DevMode { /** * Don't do any extra sanity checks. */ OFF, /** * After the initial parse */ START, /** * At the start and at the end of all optimizations. */ START_AND_END, /** * After every pass */ EVERY_PASS } public static enum TracerMode { ALL, // Collect all timing and size metrics. FAST, // Collect all timing and size metrics, except gzipped size. OFF; // Collect no timing and size metrics. boolean isOn() { return this != OFF; } } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>/* * Copyright 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; /** * An AST generated totally by the compiler. * * @author nicksantos@google.com (Nick Santos) */ class SyntheticAst implements SourceAst { private static final long serialVersionUID = 1L; private final String sourceName; private Node root; SyntheticAst(String sourceName) { this.sourceName = sourceName; clearAst(); } @Override public Node getAstRoot(AbstractCompiler compiler) { return root; } @Override public void clearAst() { root = new Node(Token.SCRIPT); root.putProp(Node.SOURCENAME_PROP, sourceName); } @Override public SourceFile getSourceFile() { return null; } @Override public void setSourceFile(SourceFile file) { throw new IllegalStateException( "Cannot set a source file for a synthetic AST"); } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> @Override public TernaryValue testForEquality(JSType that) { if (UNKNOWN.equals(super.testForEquality(that))) { return UNKNOWN; } if (that.isUnknownType() || that.isSubtype( getNativeType(JSTypeNative.OBJECT_NUMBER_STRING_BOOLEAN))) { return UNKNOWN; } return FALSE; } @Override public boolean isStringValueType() { return true; } @Override public boolean matchesNumberContext() { return true; } @Override public boolean matchesStringContext() { return true; } @Override public boolean matchesObjectContext() { // TODO(user): Revisit this for ES4, which is stricter. return true; } @Override public String toString() { return "string"; } @Override public JSType autoboxesTo() { return getNativeType(JSTypeNative.STRING_OBJECT_TYPE); } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.BOTH; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseStringType(); } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>/* * Copyright 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.collect.Lists; import com.google.javascript.jscomp.CheckLevel; import java.util.*; /** * WarningsGuard that represents just a chain of other guards. For example we * could have following chain * 1) all warnings outside of /foo/ should be suppressed * 2) errors with key JSC_BAR should be marked as warning * 3) the rest should be reported as error * * This class is designed for such behaviour. * * @author anatol@google.com (Anatol Pomazau) */ public class ComposeWarningsGuard extends WarningsGuard { private final List<WarningsGuard> guards; private static final Comparator<WarningsGuard> guardComparator = new Comparator<WarningsGuard>() { @Override public int compare(WarningsGuard a, WarningsGuard b) { return a.getPriority() - b.getPriority(); } }; public ComposeWarningsGuard(List<WarningsGuard> guards) { this.guards = Lists.newArrayList(); addGuards(guards); } public ComposeWarningsGuard(WarningsGuard... guards) { this(Lists.newArrayList(guards)); } void addGuard(WarningsGuard guard) { if (guard instanceof ComposeWarningsGuard) { addGuards(((ComposeWarningsGuard) guard).guards); } else { int index = Collections.binarySearch(this.guards, guard, guardComparator); if (index < 0) { index = -index - 1;

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> } this.guards.add(index, guard); } } private void addGuards(Iterable<WarningsGuard> guards) { for (WarningsGuard guard : guards) { addGuard(guard); } } @Override public CheckLevel level(JSError error) { for (WarningsGuard guard : guards) { CheckLevel newLevel = guard.level(error); if (newLevel != null) { return newLevel; } } return null; } @Override public boolean disables(DiagnosticGroup group) { nextSingleton: for (DiagnosticType type : group.getTypes()) { DiagnosticGroup singleton = DiagnosticGroup.forType(type); for (WarningsGuard guard : guards) { if (guard.disables(singleton)) { continue nextSingleton; } else if (guard.enables(singleton)) { return false; } } return false; } return true; } /** * Determines whether this guard will "elevate" the status of any disabled * diagnostic type in the group to a warning or an error. */ @Override public boolean enables(DiagnosticGroup group) { for (WarningsGuard guard : guards) { if (guard.enables(group)) { return true; } } return false; } List<WarningsGuard> getGuards() { return Collections.unmodifiableList(guards); } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> it. */ static JSModule[] createModuleChain(String... inputs) { JSModule[] modules = createModules(inputs); for (int i = 1; i < modules.length; i++) { modules[i].addDependency(modules[i - 1]); } return modules; } /** * Generates a list of modules from a list of inputs, such that each module * depends on the first module. */ static JSModule[] createModuleStar(String... inputs) { JSModule[] modules = createModules(inputs); for (int i = 1; i < modules.length; i++) { modules[i].addDependency(modules[0]); } return modules; } /** * Generates a list of modules from a list of inputs. Does not generate any * dependencies between the modules. */ static JSModule[] createModules(String... inputs) { JSModule[] modules = new JSModule[inputs.length]; for (int i = 0; i < inputs.length; i++) { JSModule module = modules[i] = new JSModule("m" + i); module.add(JSSourceFile.fromCode("i" + i, inputs[i])); } return modules; } private static class BlackHoleErrorManager extends BasicErrorManager { private BlackHoleErrorManager(Compiler compiler) { compiler.setErrorManager(this); } @Override public void println(CheckLevel level, JSError error) {} @Override public void printSummary() {} } private Compiler createCompiler() { Compiler compiler = new Compiler(); return compiler; } protected void setExpectedSymbolTableError(DiagnosticType type) { this.expectedSymbolTableError = type; } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>Type) { super(registry, objectType); this.indexType = indexType; } @Override public JSType getIndexType() { return indexType; } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>Native. private final boolean isChecked; UnknownType(JSTypeRegistry registry, boolean isChecked) { super(registry); this.isChecked = isChecked; } @Override public boolean isUnknownType() { return true; } @Override public boolean isCheckedUnknownType() { return isChecked; } @Override public boolean canAssignTo(JSType that) { return true; } @Override public boolean canBeCalled() { return true; } @Override public boolean matchesNumberContext() { return true; } @Override public boolean matchesObjectContext() { return true; } @Override public boolean matchesStringContext() { return true; } @Override public TernaryValue testForEquality(JSType that) { return UNKNOWN; } @Override public boolean isNullable() { return true; } @Override public boolean isSubtype(JSType that) { return true; } @Override public JSType getLeastSupertype(JSType that) { return this; } @Override public JSType getGreatestSubtype(JSType that) { return this; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseUnknownType(); } @Override public String toString() { return getReferenceName(); } @Override boolean defineProperty(String propertyName, JSType type, boolean inferred, boolean inExterns) { // nothing to define return true; } @Override public ObjectType getImplicitPrototype() { return null; } @Override public int getPropertiesCount() { return Integer.MAX_VALUE; } @Override void collectPropertyNames(Set<String> props) { } @Override public JSType getPropertyType(String propertyName) { return this; } @Override public boolean hasProperty(String propertyName) { return true; } @Override public FunctionType getConstructor() { return null; } @Override public String getReferenceName() { return isChecked ? "??" : "?"; } @Override public boolean isPropertyTypeDeclared(String propertyName) { return false; } @Override

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> public boolean isPropertyTypeInferred(String propertyName) { return false; } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.BOTH; } @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) { return this; } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> reference is resolved. * * The {@code UnresolvedType} will behave like an opaque unknown type. * When its {@code #resolve} method is called, it will return the underlying * type. The underlying type can resolve to any JS type.<p> * * @author nicksantos@google.com (Nick Santos) */ class UnresolvedTypeExpression extends UnknownType { private static final long serialVersionUID = 1L; private final Node typeExpr; private final String sourceName; /** * If true, don't warn about unresolveable type names. * * NOTE(nicksantos): A lot of third-party code doesn't use our type syntax. * They have code like * {@code @return} the bus. * and they clearly don't mean that "the" is a type. In these cases, we're * forgiving and try to guess whether or not "the" is a type when it's not * clear. */ private boolean forgiving = false; /** * Create a named type based on the reference. */ UnresolvedTypeExpression(JSTypeRegistry registry, Node typeExpr, String sourceName, boolean forgiving) { super(registry, false); Preconditions.checkNotNull(typeExpr); this.typeExpr = typeExpr; this.sourceName = sourceName; this.forgiving = forgiving; } /** * Resolve the referenced type within the enclosing scope. */ @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> enclosing) { return registry.createFromTypeNodes(typeExpr, sourceName, enclosing, forgiving); } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>IN_EXTERNS_ERROR = DiagnosticType.warning( "JSC_NAME_REFERENCE_IN_EXTERNS", "accessing name {0} in externs has no effect"); static final DiagnosticType UNDEFINED_EXTERN_VAR_ERROR = DiagnosticType.disabled( "JSC_UNDEFINED_EXTERN_VAR_ERROR", "name {0} is not undefined in the externs."); static final DiagnosticType INVALID_FUNCTION_DECL = DiagnosticType.error("JSC_INVALID_FUNCTION_DECL", "Syntax error: function declaration must have a name"); private CompilerInput synthesizedExternsInput = null; private Node synthesizedExternsRoot = null; private final AbstractCompiler compiler; // Whether this is the post-processing sanity check. private final boolean sanityCheck; // Whether extern checks emit error. private boolean strictExternCheck; VarCheck(AbstractCompiler compiler) { this(compiler, false); } VarCheck(AbstractCompiler compiler, boolean sanityCheck) { this.compiler = compiler; this.strictExternCheck = compiler.getErrorLevel( JSError.make("", 0, 0, UNDEFINED_EXTERN_VAR_ERROR)) == CheckLevel.ERROR; this.sanityCheck = sanityCheck; } @Override public void process(Node externs, Node root) { NodeTraversal.traverse(compiler, externs, new NameRefInExternsCheck()); NodeTraversal.traverseRoots( compiler, Lists.newArrayList(externs, root), this); } @Override public void visit(NodeTraversal t, Node n, Node parent) { if (n.getType() != Token.NAME) { return; } String varName = n.getString(); // Only a function can have an empty name. if (varName.isEmpty()) { Preconditions.checkState(NodeUtil.isFunction(parent)); // A function declaration with an empty name passes Rhino, // but is supposed to be a syntax error according to the spec. if (!NodeUtil.isFunctionExpression(parent)) { t.report(n, INVALID_FUNCTION_DECL); } return; } // Check that the var has been declared. Scope scope = t.getScope(); Scope.Var var = scope

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>.isGlobal()) { if (moduleGraph.dependsOn(varModule, currModule)) { // The variable reference violates a declared module dependency. t.report(n, VIOLATED_MODULE_DEP_ERROR, currModule.getName(), varModule.getName(), varName); } else { // The variable reference is between two modules that have no // dependency relationship. This should probably be considered an // error, but just issue a warning for now. t.report(n, MISSING_MODULE_DEP_ERROR, currModule.getName(), varModule.getName(), varName); } } else { t.report(n, STRICT_MODULE_DEP_ERROR, currModule.getName(), varModule.getName(), varName); } } } } /** * A check for name references in the externs inputs. These used to prevent * a variable from getting renamed, but no longer have any effect. */ private class NameRefInExternsCheck extends AbstractPostOrderCallback { public void visit(NodeTraversal t, Node n, Node parent) { if (n.getType() == Token.NAME) { switch (parent.getType()) { case Token.VAR: case Token.FUNCTION: case Token.LP: // These are okay. break; case Token.GETPROP: if (n == parent.getFirstChild()) { Scope scope = t.getScope(); Scope.Var var = scope.getVar(n.getString()); if (var == null) { t.report(n, UNDEFINED_EXTERN_VAR_ERROR, n.getString()); } } break; default: t.report(n, NAME_REFERENCE_IN_EXTERNS_ERROR, n.getString()); break; } } } } /** Lazily create a "new" externs input for undeclared variables. */ private CompilerInput getSynthesizedExternsInput() { if (synthesizedExternsInput == null) { synthesizedExternsInput = compiler.newExternInput("{SyntheticVarsDeclar}"); } return synthesizedExternsInput; } /** Lazily create a "new" externs root for undeclared variables. */ private Node getSynt

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> { private static final long serialVersionUID = 1L; VoidType(JSTypeRegistry registry) { super(registry); } @Override public JSType restrictByNotNullOrUndefined() { return registry.getNativeType(JSTypeNative.NO_TYPE); } @Override public TernaryValue testForEquality(JSType that) { if (UNKNOWN.equals(super.testForEquality(that))) { return UNKNOWN; } if (that.isSubtype(this) || that.isSubtype(getNativeType(JSTypeNative.NULL_TYPE))) { return TRUE; } return FALSE; } @Override public boolean matchesNumberContext() { return false; } @Override public boolean matchesObjectContext() { return false; } @Override public boolean matchesStringContext() { return true; } @Override public boolean isVoidType() { return true; } @Override public String toString() { return "undefined"; } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.FALSE; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseVoidType(); } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> /** Gets the module name. */ public String getName() { return name; } @Override public List<String> getProvides() { return ImmutableList.<String>of(name); } @Override public List<String> getRequires() { ImmutableList.Builder<String> builder = ImmutableList.builder(); for (JSModule m : deps) { builder.add(m.getName()); } return builder.build(); } @Override public String getPathRelativeToClosureBase() { throw new UnsupportedOperationException(); } /** Adds a source file input to this module. */ public void add(JSSourceFile file) { add(new CompilerInput(file)); } /** Adds a source file input to this module. */ public void addFirst(JSSourceFile file) { addFirst(new CompilerInput(file)); } /** Adds a source code input to this module. */ public void add(CompilerInput input) { inputs.add(input); input.setModule(this); } /** Adds a source code input to this module. */ public void addFirst(CompilerInput input) { inputs.add(0, input); input.setModule(this); } /** Adds a source code input to this module directly after other. */ public void addAfter(CompilerInput input, CompilerInput other) { Preconditions.checkState(inputs.contains(other)); inputs.add(inputs.indexOf(other), input); input.setModule(this); } /** Adds a dependency on another module. */ public void addDependency(JSModule dep) { Preconditions.checkState(dep != this); deps.add(dep); } /** Removes an input from this module. */ public void remove(CompilerInput input) { input.setModule(null); inputs.remove(input); } /** Removes all of the inputs from this module. */ public void removeAll() { for (CompilerInput input : inputs) { input.setModule(null); } inputs.clear(); } /** * Gets the list of modules that this module depends on. * * @return A list that may be empty but not null */ public List<JSModule> getDependencies() { return deps; }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> /** * Gets the names of the modules that this module depends on, * sorted alphabetically. */ List<String> getSortedDependencyNames() { List<String> names = Lists.newArrayList(); for (JSModule module : getDependencies()) { names.add(module.getName()); } Collections.sort(names); return names; } /** * Returns the transitive closure of dependencies starting from the * dependencies of this module. */ public Set<JSModule> getAllDependencies() { Set<JSModule> allDeps = Sets.newHashSet(deps); List<JSModule> workList = Lists.newArrayList(deps); while (workList.size() > 0) { JSModule module = workList.remove(workList.size() - 1); for (JSModule dep : module.getDependencies()) { if (allDeps.add(dep)) { workList.add(dep); } } } return allDeps; } /** Returns this module and all of its dependencies in one list. */ public Set<JSModule> getThisAndAllDependencies() { Set<JSModule> deps = getAllDependencies(); deps.add(this); return deps; } /** * Gets this module's list of source code inputs. * * @return A list that may be empty but not null */ public List<CompilerInput> getInputs() { return inputs; } /** Returns the input with the given name or null if none. */ public CompilerInput getByName(String name) { for (CompilerInput input : inputs) { if (name.equals(input.getName())) { return input; } } return null; } /** * Removes any input with the given name. Returns whether any were removed. */ public boolean removeByName(String name) { boolean found = false; Iterator<CompilerInput> iter = inputs.iterator(); while (iter.hasNext()) { CompilerInput file = iter.next(); if (name.equals(file.getName())) { iter.remove(); file.setModule(null); found = true; } } return found; } /** Returns the module name (primarily for debugging). */ @Override

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> qualifiedName = node.getQualifiedName(); Preconditions.checkNotNull(qualifiedName); JSType origType = node.getJSType(); origType = origType == null ? getNativeType(UNKNOWN_TYPE) : origType; scope.inferQualifiedSlot(qualifiedName, origType, type); break; default: throw new IllegalArgumentException("Node cannot be refined. \n" + node.toStringTree()); } } /** * @see #getRestrictedWithoutUndefined(JSType) */ private final Visitor<JSType> restrictUndefinedVisitor = new Visitor<JSType>() { public JSType caseEnumElementType(EnumElementType enumElementType) { JSType type = enumElementType.getPrimitiveType().visit(this); if (type != null && enumElementType.getPrimitiveType().equals(type)) { return enumElementType; } else { return type; } } public JSType caseAllType() { return typeRegistry.createUnionType(OBJECT_TYPE, NUMBER_TYPE, STRING_TYPE, BOOLEAN_TYPE, NULL_TYPE); } public JSType caseNoObjectType() { return getNativeType(NO_OBJECT_TYPE); } public JSType caseNoType() { return getNativeType(NO_TYPE); } public JSType caseBooleanType() { return getNativeType(BOOLEAN_TYPE); } public JSType caseFunctionType(FunctionType type) { return type; } public JSType caseNullType() { return getNativeType(NULL_TYPE); } public JSType caseNumberType() { return getNativeType(NUMBER_TYPE); } public JSType caseObjectType(ObjectType type) { return type; } public JSType caseStringType() { return getNativeType(STRING_TYPE); } public JSType caseUnionType(UnionType type) { return type.getRestrictedUnion(getNativeType(VOID_TYPE)); } public JSType caseUnknownType() { return getNativeType(UNKNOWN_TYPE); } public JSType caseVoidType() { return null; } }; /** * @see #getRestrictedWithoutNull(JSType) */ private final Visitor<JSType> restrictNullVisitor = new Visitor<JSType>() { public JS

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>Type caseEnumElementType(EnumElementType enumElementType) { JSType type = enumElementType.getPrimitiveType().visit(this); if (type != null && enumElementType.getPrimitiveType().equals(type)) { return enumElementType; } else { return type; } } public JSType caseAllType() { return typeRegistry.createUnionType(OBJECT_TYPE, NUMBER_TYPE, STRING_TYPE, BOOLEAN_TYPE, VOID_TYPE); } public JSType caseNoObjectType() { return getNativeType(NO_OBJECT_TYPE); } public JSType caseNoType() { return getNativeType(NO_TYPE); } public JSType caseBooleanType() { return getNativeType(BOOLEAN_TYPE); } public JSType caseFunctionType(FunctionType type) { return type; } public JSType caseNullType() { return null; } public JSType caseNumberType() { return getNativeType(NUMBER_TYPE); } public JSType caseObjectType(ObjectType type) { return type; } public JSType caseStringType() { return getNativeType(STRING_TYPE); } public JSType caseUnionType(UnionType type) { return type.getRestrictedUnion(getNativeType(NULL_TYPE)); } public JSType caseUnknownType() { return getNativeType(UNKNOWN_TYPE); } public JSType caseVoidType() { return getNativeType(VOID_TYPE); } }; /** * A class common to all visitors that need to restrict the type based on * {@code typeof}-like conditions. */ abstract class RestrictByTypeOfResultVisitor implements Visitor<JSType> { /** * Abstracts away the similarities between visiting the unknown type and the * all type. * @param topType {@code UNKNOWN_TYPE} or {@code ALL_TYPE} * @return the restricted type * @see #caseAllType * @see #caseUnknownType */ protected abstract JSType caseTopType(JSType topType); public JSType caseAllType() { return caseTopType(getNativeType(ALL_TYPE)); } public JSType caseUnknownType() { return caseTopType(getNativeType(UNKNOWN_TYPE

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>)); } public JSType caseUnionType(UnionType type) { JSType restricted = null; for (JSType alternate : type.getAlternates()) { JSType restrictedAlternate = alternate.visit(this); if (restrictedAlternate != null) { if (restricted == null) { restricted = restrictedAlternate; } else { restricted = restrictedAlternate.getLeastSupertype(restricted); } } } return restricted; } public JSType caseNoType() { return getNativeType(NO_TYPE); } public JSType caseEnumElementType(EnumElementType enumElementType) { // NOTE(nicksantos): This is a white lie. Suppose we have: // /** @enum {string|number} */ var MyEnum = ...; // if (goog.isNumber(myEnumInstance)) { // /* what is myEnumInstance here? */ // } // There is no type that represents {MyEnum - string}. What we really // need is a notion of "enum subtyping", so that we could dynamically // create a subtype of MyEnum restricted by string. In any case, // this should catch the common case. JSType type = enumElementType.getPrimitiveType().visit(this); if (type != null && enumElementType.getPrimitiveType().equals(type)) { return enumElementType; } else { return type; } } } /** * A class common to all visitors that need to restrict the type based on * some {@code typeof}-like condition being true. All base cases return * {@code null}. It is up to the subclasses to override the appropriate ones. */ abstract class RestrictByTrueTypeOfResultVisitor extends RestrictByTypeOfResultVisitor { public JSType caseNoObjectType() { return null; } public JSType caseBooleanType() { return null; } public JSType caseFunctionType(FunctionType type) { return null; } public JSType caseNullType() { return null; } public JSType caseNumberType() { return null; } public JSType caseObjectType(ObjectType type) { return null; } public JSType caseStringType() { return null; } public JSType caseVoidType() { return null

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>; } } /** * A class common to all visitors that need to restrict the type based on * some {@code typeof}-like condition being false. All base cases return * their type. It is up to the subclasses to override the appropriate ones. */ abstract class RestrictByFalseTypeOfResultVisitor extends RestrictByTypeOfResultVisitor { @Override protected JSType caseTopType(JSType topType) { return topType; } public JSType caseNoObjectType() { return getNativeType(NO_OBJECT_TYPE); } public JSType caseBooleanType() { return getNativeType(BOOLEAN_TYPE); } public JSType caseFunctionType(FunctionType type) { return type; } public JSType caseNullType() { return getNativeType(NULL_TYPE); } public JSType caseNumberType() { return getNativeType(NUMBER_TYPE); } public JSType caseObjectType(ObjectType type) { return type; } public JSType caseStringType() { return getNativeType(STRING_TYPE); } public JSType caseVoidType() { return getNativeType(VOID_TYPE); } } /** * @see ChainableReverseAbstractInterpreter#getRestrictedByTypeOfResult */ private class RestrictByOneTypeOfResultVisitor extends RestrictByTypeOfResultVisitor { /** * A value known to be equal or not equal to the result of the * {@code typeOf} operation. */ private final String value; /** * {@code true} if the {@code typeOf} result is known to equal * {@code value}; {@code false} if it is known <em>not</em> to equal * {@code value}. */ private final boolean resultEqualsValue; RestrictByOneTypeOfResultVisitor(String value, boolean resultEqualsValue) { this.value = value; this.resultEqualsValue = resultEqualsValue; } /** * Computes whether the given result of a {@code typeof} operator matches * expectations, i.e. whether a type that gives such a result should be * kept. */ private boolean matchesExpectation(String result) { return result.equals(value) == resultEqualsValue; } @Override protected JSType caseTopType

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>(JSType topType) { JSType result = topType; if (resultEqualsValue) { JSType typeByName = getNativeTypeForTypeOf(value); if (typeByName != null) { result = typeByName; } } return result; } public JSType caseNoObjectType() { return (value.equals("object") || value.equals("function")) == resultEqualsValue ? getNativeType(NO_OBJECT_TYPE) : null; } public JSType caseBooleanType() { return matchesExpectation("boolean") ? getNativeType(BOOLEAN_TYPE) : null; } public JSType caseFunctionType(FunctionType type) { return matchesExpectation("function") ? type : null; } public JSType caseNullType() { return matchesExpectation("object") ? getNativeType(NULL_TYPE) : null; } public JSType caseNumberType() { return matchesExpectation("number") ? getNativeType(NUMBER_TYPE) : null; } public JSType caseObjectType(ObjectType type) { if (value.equals("function")) { JSType ctorType = getNativeType(U2U_CONSTRUCTOR_TYPE); return resultEqualsValue && ctorType.isSubtype(type) ? ctorType : null; } return matchesExpectation("object") ? type : null; } public JSType caseStringType() { return matchesExpectation("string") ? getNativeType(STRING_TYPE) : null; } public JSType caseVoidType() { return matchesExpectation("undefined") ? getNativeType(VOID_TYPE) : null; } } /** * Returns a version of type where undefined is not present. */ final JSType getRestrictedWithoutUndefined(JSType type) { return type == null ? null : type.visit(restrictUndefinedVisitor); } /** * Returns a version of type where null is not present. */ final JSType getRestrictedWithoutNull(JSType type) { return type == null ? null : type.visit(restrictNullVisitor); } /** * Returns a version of {@code type} that is restricted by some knowledge * about the result of the {@code typeof} operation. * <p> * The behavior of the {@code typeof} operator can be summarized

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> by the * following table: * <table> * <tr><th>type</th><th>result</th></tr> * <tr><td>{@code undefined}</td><td>"undefined"</td></tr> * <tr><td>{@code null}</td><td>"object"</td></tr> * <tr><td>{@code boolean}</td><td>"boolean"</td></tr> * <tr><td>{@code number}</td><td>"number"</td></tr> * <tr><td>{@code string}</td><td>"string"</td></tr> * <tr><td>{@code Object} (which doesn't implement [[Call]])</td> * <td>"object"</td></tr> * <tr><td>{@code Object} (which implements [[Call]])</td> * <td>"function"</td></tr> * </table> * @param type the type to restrict * @param value A value known to be equal or not equal to the result of the * {@code typeof} operation * @param resultEqualsValue {@code true} if the {@code typeOf} result is known * to equal {@code value}; {@code false} if it is known <em>not</em> to * equal {@code value} * @return the restricted type or null if no version of the type matches the * restriction */ JSType getRestrictedByTypeOfResult(JSType type, String value, boolean resultEqualsValue) { if (type == null) { if (resultEqualsValue) { JSType result = getNativeTypeForTypeOf(value); return result == null ? getNativeType(UNKNOWN_TYPE) : result; } else { return null; } } return type.visit( new RestrictByOneTypeOfResultVisitor(value, resultEqualsValue)); } JSType getNativeType(JSTypeNative typeId) { return typeRegistry.getNativeType(typeId); } /** * If we definitely know what a type is based on the typeof result, * return it. Otherwise, return null. * * The typeof operation in JS is poorly defined, and this function works * for both the native typeof and goog.typeOf. It should not be

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> outerThis = this; final Scope outerScope = t.getScope(); final FunctionType functionType = (FunctionType) n.getJSType(); final String functionPrivateName = n.getFirstChild().getString(); if (functionPrivateName != null && functionPrivateName.length() > 0 && outerScope.isDeclared(functionPrivateName, false) && // Ideally, we would want to check whether the type in the scope // differs from the type being defined, but then the extern // redeclarations of built-in types generates spurious warnings. !(outerScope.getVar( functionPrivateName).getType() instanceof FunctionType)) { report(t, n, FUNCTION_MASKS_VARIABLE, functionPrivateName); } // TODO(user): Only traverse the function's body. The function's // name and arguments are traversed by the scope creator, and ideally // should not be traversed by the type checker. break; } return true; } /** * This is the meat of the type checking. It is basically one big switch, * with each case representing one type of parse tree node. The individual * cases are usually pretty straightforward. * * @param t The node traversal object that supplies context, such as the * scope chain to use in name lookups as well as error reporting. * @param n The node being visited. * @param parent The parent of the node n. */ public void visit(NodeTraversal t, Node n, Node parent) { JSType childType; JSType leftType, rightType; Node left, right; // To be explicitly set to false if the node is not typeable. boolean typeable = true; switch (n.getType()) { case Token.NAME: typeable = visitName(t, n, parent); break; case Token.LP: // If this is under a FUNCTION node, it is a parameter list and can be // ignored here. if (parent.getType() != Token.FUNCTION) { ensureTyped(t, n, getJSType(n.getFirstChild())); } else { typeable = false; } break; case Token.COMMA: ensureTyped(t, n, getJSType(n.getLastChild()));

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> getJSType(left), "increment/decrement"); ensureTyped(t, n, NUMBER_TYPE); break; case Token.NOT: ensureTyped(t, n, BOOLEAN_TYPE); break; case Token.VOID: ensureTyped(t, n, VOID_TYPE); break; case Token.TYPEOF: ensureTyped(t, n, STRING_TYPE); break; case Token.BITNOT: childType = getJSType(n.getFirstChild()); if (!childType.matchesInt32Context()) { report(t, n, BIT_OPERATION, NodeUtil.opToStr(n.getType()), childType.toString()); } ensureTyped(t, n, NUMBER_TYPE); break; case Token.POS: case Token.NEG: left = n.getFirstChild(); validator.expectNumber(t, left, getJSType(left), "sign operator"); ensureTyped(t, n, NUMBER_TYPE); break; case Token.EQ: case Token.NE: { leftType = getJSType(n.getFirstChild()); rightType = getJSType(n.getLastChild()); JSType leftTypeRestricted = leftType.restrictByNotNullOrUndefined(); JSType rightTypeRestricted = rightType.restrictByNotNullOrUndefined(); TernaryValue result = leftTypeRestricted.testForEquality(rightTypeRestricted); if (result != TernaryValue.UNKNOWN) { if (n.getType() == Token.NE) { result = result.not(); } report(t, n, DETERMINISTIC_TEST, leftType.toString(), rightType.toString(), result.toString()); } ensureTyped(t, n, BOOLEAN_TYPE); break; } case Token.SHEQ: case Token.SHNE: { leftType = getJSType(n.getFirstChild()); rightType = getJSType(n.getLastChild()); JSType leftTypeRestricted = leftType.restrictByNotNullOrUndefined(); JSType rightTypeRestricted = rightType.restrictByNotNullOrUndefined(); if (!leftTypeRestricted.canTestForShallowEqualityWith( rightTypeRestricted)) { report(t, n, DETERMINISTIC_TEST_NO_RESULT, leftType

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>/* * Copyright 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; /** * A factory for creating JSCompiler passes based on the Options * injected. Contains all meta-data about compiler passes (like * whether it can be run multiple times, a human-readable name for * logging, etc.). * * @author nicksantos@google.com (Nick Santos) */ public abstract class PassFactory { private final String name; private final boolean isOneTimePass; private boolean isCreated = false; /** * @param name The name of the pass that this factory creates. * @param isOneTimePass If true, the pass produced by this factory can * only be run once. */ protected PassFactory(String name, boolean isOneTimePass) { this.name = name; this.isOneTimePass = isOneTimePass; } /** * @return The name of this pass. */ String getName() { return name; } /** * @return Whether the pass produced by this factory can only be run once. */ boolean isOneTimePass() { return isOneTimePass; } /** * Make a new pass factory that only creates one-time passes. */ PassFactory makeOneTimePass() { if (isOneTimePass()) { return this; } final PassFactory self = this; return new PassFactory(name, true /* one time pass */) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return self.createInternal(compiler); }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>/* * Copyright 2010 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.Node; /** * Look for references to the global RegExp object that would cause * regular expressions to be unoptimizable. * * @author johnlenz@google.com (John Lenz) */ class CheckRegExp extends AbstractPostOrderCallback implements CompilerPass { static final DiagnosticType REGEXP_REFERENCE = DiagnosticType.warning("JSC_REGEXP_REFERENCE", "References to the global RegExp object prevents " + "optimization of regular expressions."); private final AbstractCompiler compiler; private boolean globalRegExpPropertiesUsed = false; public boolean isGlobalRegExpPropertiesUsed() { return globalRegExpPropertiesUsed; } public CheckRegExp(AbstractCompiler compiler) { this.compiler = compiler; } @Override public void process(Node externs, Node root) { NodeTraversal.traverse(compiler, root, this); } @Override public void visit(NodeTraversal t, Node n, Node parent) { if (NodeUtil.isReferenceName(n)) { String name = n.getString(); if (name.equals("RegExp") && t.getScope().getVar(name) == null) { int parentType = parent.getType(); boolean first = (n == parent.getFirstChild()); if (!((parentType == Token.NEW && first) || (parentType == Token.CALL && first) || (parentType == Token.INSTANCEOF && !

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>.STRING); } return ret; } @Override Node processArrayLiteral(ArrayLiteral literalNode) { if (literalNode.isDestructuring()) { reportDestructuringAssign(literalNode); } Node node = newNode(Token.ARRAYLIT); int skipCount = 0; for (AstNode child : literalNode.getElements()) { Node c = transform(child); if (c.getType() == Token.EMPTY) { skipCount++; } node.addChildToBack(c); } if (skipCount > 0) { int[] skipIndexes = new int[skipCount]; int i = 0; int j = 0; for (Node child : node.children()) { if (child.getType() == Token.EMPTY) { node.removeChild(child); skipIndexes[j] = i; j++; } i++; } node.putProp(Node.SKIP_INDEXES_PROP, skipIndexes); } return node; } @Override Node processAssignment(Assignment assignmentNode) { return processInfixExpression(assignmentNode); } @Override Node processAstRoot(AstRoot rootNode) { Node node = newNode(Token.SCRIPT); for (com.google.javascript.jscomp.mozilla.rhino.Node child : rootNode) { node.addChildToBack(transform((AstNode)child)); } parseDirectives(node); return node; } /** * Parse the directives, encode them in the AST, and remove their nodes. * * For information on ES5 directives, see section 14.1 of * Ecma-262, Edition 5. * * It would be nice if Rhino would eventually take care of this for * us, but right now their directive-processing is a one-off. */ private void parseDirectives(Node node) { // Remove all the directives, and encode them in the AST. Set<String> directives = null; while (isDirective(node.getFirstChild())) { String directive = node.removeFirstChild().getFirstChild().getString(); if (directives == null) { directives = Sets.newHashSet(directive); } else { directives.

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>add(directive); } } if (directives != null) { node.setDirectives(directives); } } private boolean isDirective(Node n) { if (n == null) return false; int nType = n.getType(); return (nType == Token.EXPR_RESULT || nType == Token.EXPR_VOID) && n.getFirstChild().getType() == Token.STRING && ALLOWED_DIRECTIVES.contains(n.getFirstChild().getString()); } @Override Node processBlock(Block blockNode) { return processGeneric(blockNode); } @Override Node processBreakStatement(BreakStatement statementNode) { Node node = newNode(Token.BREAK); if (statementNode.getBreakLabel() != null) { Node labelName = transform(statementNode.getBreakLabel()); // Change the NAME to LABEL_NAME labelName.setType(Token.LABEL_NAME); node.addChildToBack(labelName); } return node; } @Override Node processCatchClause(CatchClause clauseNode) { AstNode catchVar = clauseNode.getVarName(); Node node = newNode(Token.CATCH, transform(catchVar)); if (clauseNode.getCatchCondition() != null) { node.addChildToBack(transform(clauseNode.getCatchCondition())); } else { Node catchCondition = newNode(Token.EMPTY); // Old Rhino used the position of the catchVar as the position // for the (nonexistent) error being caught. catchCondition.setLineno(catchVar.getLineno()); int clauseAbsolutePosition = position2charno(catchVar.getAbsolutePosition()); catchCondition.setCharno(clauseAbsolutePosition); node.addChildToBack(catchCondition); } node.addChildToBack(transformBlock(clauseNode.getBody())); return node; } @Override Node processConditionalExpression(ConditionalExpression exprNode) { return newNode( Token.HOOK, transform(exprNode.getTestExpression()), transform(exprNode.getTrueExpression()), transform(exprNode.getFalseExpression())); } @Override Node processContinueStatement(ContinueStatement statementNode) { Node node = newNode(Token.CONTINUE); if (statementNode.getLabel() !=

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> null) { Node labelName = transform(statementNode.getLabel()); // Change the NAME to LABEL_NAME labelName.setType(Token.LABEL_NAME); node.addChildToBack(labelName); } return node; } @Override Node processDoLoop(DoLoop loopNode) { return newNode( Token.DO, transformBlock(loopNode.getBody()), transform(loopNode.getCondition())); } @Override Node processElementGet(ElementGet getNode) { return newNode( Token.GETELEM, transform(getNode.getTarget()), transform(getNode.getElement())); } @Override Node processEmptyExpression(EmptyExpression exprNode) { Node node = newNode(Token.EMPTY); return node; } @Override Node processExpressionStatement(ExpressionStatement statementNode) { Node node = newNode(transformTokenType(statementNode.getType())); node.addChildToBack(transform(statementNode.getExpression())); return node; } @Override Node processForInLoop(ForInLoop loopNode) { return newNode( Token.FOR, transform(loopNode.getIterator()), transform(loopNode.getIteratedObject()), transformBlock(loopNode.getBody())); } @Override Node processForLoop(ForLoop loopNode) { Node node = newNode( Token.FOR, transform(loopNode.getInitializer()), transform(loopNode.getCondition()), transform(loopNode.getIncrement())); node.addChildToBack(transformBlock(loopNode.getBody())); return node; } @Override Node processFunctionCall(FunctionCall callNode) { Node node = newNode(transformTokenType(callNode.getType()), transform(callNode.getTarget())); for (AstNode child : callNode.getArguments()) { node.addChildToBack(transform(child)); } int leftParamPos = callNode.getAbsolutePosition() + callNode.getLp(); node.setLineno(callNode.getLineno()); node.setCharno(position2charno(leftParamPos)); return node; } @Override Node processFunctionNode(FunctionNode functionNode) { Name name = functionNode.getFunctionName(); Boolean isUnnamedFunction = false; if (name == null

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>) { name = new Name(); name.setIdentifier(""); isUnnamedFunction = true; } Node node = newNode(Token.FUNCTION); node.putProp(Node.SOURCENAME_PROP, functionNode.getSourceName()); Node newName = transform(name); if (isUnnamedFunction) { // Old Rhino tagged the empty name node with the line number of the // declaration. newName.setLineno(functionNode.getLineno()); // TODO(bowdidge) Mark line number of paren correctly. // Same problem as below - the left paren might not be on the // same line as the function keyword. int lpColumn = functionNode.getAbsolutePosition() + functionNode.getLp(); newName.setCharno(position2charno(lpColumn)); } node.addChildToBack(newName); Node lp = newNode(Token.LP); // The left paren's complicated because it's not represented by an // AstNode, so there's nothing that has the actual line number that it // appeared on. We know the paren has to appear on the same line as the // function name (or else a semicolon will be inserted.) If there's no // function name, assume the paren was on the same line as the function. // TODO(bowdidge): Mark line number of paren correctly. Name fnName = functionNode.getFunctionName(); if (fnName != null) { lp.setLineno(fnName.getLineno()); } else { lp.setLineno(functionNode.getLineno()); } int lparenCharno = functionNode.getLp() + functionNode.getAbsolutePosition(); lp.setCharno(position2charno(lparenCharno)); for (AstNode param : functionNode.getParams()) { lp.addChildToBack(transform(param)); } node.addChildToBack(lp); Node bodyNode = transform(functionNode.getBody()); parseDirectives(bodyNode); node.addChildToBack(bodyNode); return node; } @Override Node processIfStatement(IfStatement statementNode) { Node node = newNode(Token.IF); node.addChildToBack(transform(statementNode.

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>getCondition())); node.addChildToBack(transformBlock(statementNode.getThenPart())); if (statementNode.getElsePart() != null) { node.addChildToBack(transformBlock(statementNode.getElsePart())); } return node; } @Override Node processInfixExpression(InfixExpression exprNode) { Node n = newNode( transformTokenType(exprNode.getType()), transform(exprNode.getLeft()), transform(exprNode.getRight())); // Set the line number here so we can fine-tune it in ways transform // doesn't do. n.setLineno(exprNode.getLineno()); // Position in new ASTNode is to start of expression, but old-fashioned // line numbers from Node reference the operator token. Add the offset // to the operator to get the correct character number. n.setCharno(position2charno(exprNode.getAbsolutePosition() + exprNode.getOperatorPosition())); return n; } @Override Node processKeywordLiteral(KeywordLiteral literalNode) { return newNode(transformTokenType(literalNode.getType())); } @Override Node processLabel(Label labelNode) { return newStringNode(Token.LABEL_NAME, labelNode.getName()); } @Override Node processLabeledStatement(LabeledStatement statementNode) { Node node = newNode(Token.LABEL); Node prev = null; Node cur = node; for (Label label : statementNode.getLabels()) { if (prev != null) { prev.addChildToBack(cur); } cur.addChildToBack(transform(label)); cur.setLineno(label.getLineno()); int clauseAbsolutePosition = position2charno(label.getAbsolutePosition()); cur.setCharno(clauseAbsolutePosition); prev = cur; cur = newNode(Token.LABEL); } prev.addChildToBack(transform(statementNode.getStatement())); return node; } @Override Node processName(Name nameNode) { return newStringNode(Token.NAME, nameNode.getIdentifier()); } @Override Node processNewExpression(NewExpression exprNode) { return processFunctionCall(exprNode); } @Override Node process

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>NumberLiteral(NumberLiteral literalNode) { return newNumberNode(literalNode.getNumber()); } @Override Node processObjectLiteral(ObjectLiteral literalNode) { if (literalNode.isDestructuring()) { reportDestructuringAssign(literalNode); } Node node = newNode(Token.OBJECTLIT); for (ObjectProperty el : literalNode.getElements()) { if (el.isGetter()) { reportGetter(el); } else if (el.isSetter()) { reportSetter(el); } else { node.addChildToBack(transformAsString(el.getLeft())); node.addChildToBack(transform(el.getRight())); } } return node; } @Override Node processObjectProperty(ObjectProperty propertyNode) { return processInfixExpression(propertyNode); } @Override Node processParenthesizedExpression(ParenthesizedExpression exprNode) { Node node = transform(exprNode.getExpression()); node.putProp(Node.PARENTHESIZED_PROP, Boolean.TRUE); return node; } @Override Node processPropertyGet(PropertyGet getNode) { return newNode( Token.GETPROP, transform(getNode.getTarget()), transformAsString(getNode.getProperty())); } @Override Node processRegExpLiteral(RegExpLiteral literalNode) { Node literalStringNode = newStringNode(literalNode.getValue()); // assume it's on the same line. literalStringNode.setLineno(literalNode.getLineno()); Node node = newNode(Token.REGEXP, literalStringNode); String flags = literalNode.getFlags(); if (flags != null && !flags.isEmpty()) { Node flagsNode = newStringNode(flags); // Assume the flags are on the same line as the literal node. flagsNode.setLineno(literalNode.getLineno()); node.addChildToBack(flagsNode); } return node; } @Override Node processReturnStatement(ReturnStatement statementNode) { Node node = newNode(Token.RETURN); if (statementNode.getReturnValue() != null) { node.addChildToBack(transform(statementNode.getReturnValue())); } return node; } @Override Node processScope(Scope scopeNode) { return

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> processGeneric(scopeNode); } @Override Node processStringLiteral(StringLiteral literalNode) { Node n = newStringNode(literalNode.getValue()); return n; } @Override Node processSwitchCase(SwitchCase caseNode) { Node node; if (caseNode.isDefault()) { node = newNode(Token.DEFAULT); } else { AstNode expr = caseNode.getExpression(); node = newNode(Token.CASE, transform(expr)); } Node block = newNode(Token.BLOCK); block.putBooleanProp(Node.SYNTHETIC_BLOCK_PROP, true); block.setLineno(caseNode.getLineno()); block.setCharno(position2charno(caseNode.getAbsolutePosition())); if (caseNode.getStatements() != null) { for (AstNode child : caseNode.getStatements()) { block.addChildToBack(transform(child)); } } node.addChildToBack(block); return node; } @Override Node processSwitchStatement(SwitchStatement statementNode) { Node node = newNode(Token.SWITCH, transform(statementNode.getExpression())); for (AstNode child : statementNode.getCases()) { node.addChildToBack(transform(child)); } return node; } @Override Node processThrowStatement(ThrowStatement statementNode) { return newNode(Token.THROW, transform(statementNode.getExpression())); } @Override Node processTryStatement(TryStatement statementNode) { Node node = newNode(Token.TRY, transformBlock(statementNode.getTryBlock())); Node block = newNode(Token.BLOCK); boolean lineSet = false; for (CatchClause cc : statementNode.getCatchClauses()) { // Mark the enclosing block at the same line as the first catch // clause. if (lineSet == false) { block.setLineno(cc.getLineno()); lineSet = true; } block.addChildToBack(transform(cc)); } node.addChildToBack(block); AstNode finallyBlock = statementNode.getFinallyBlock(); if (finallyBlock != null) { node.addChildToBack(transformBlock(finallyBlock)); } // If

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> we didn't set the line on the catch clause, then // we've got an empty catch clause. Set its line to be the same // as the finally block (to match Old Rhino's behavior.) if ((lineSet == false) && (finallyBlock != null)) { block.setLineno(finallyBlock.getLineno()); } return node; } @Override Node processUnaryExpression(UnaryExpression exprNode) { int type = transformTokenType(exprNode.getType()); Node operand = transform(exprNode.getOperand()); if (type == Token.NEG && operand.getType() == Token.NUMBER) { operand.setDouble(-operand.getDouble()); return operand; } else { Node node = newNode(type, operand); if (exprNode.isPostfix()) { node.putBooleanProp(Node.INCRDECR_PROP, true); } return node; } } @Override Node processVariableDeclaration(VariableDeclaration declarationNode) { Node node = newNode(Token.VAR); for (VariableInitializer child : declarationNode.getVariables()) { node.addChildToBack(transform(child)); } return node; } @Override Node processVariableInitializer(VariableInitializer initializerNode) { Node node = transform(initializerNode.getTarget()); if (initializerNode.getInitializer() != null) { node.addChildToBack(transform(initializerNode.getInitializer())); node.setLineno(node.getLineno()); } return node; } @Override Node processWhileLoop(WhileLoop loopNode) { return newNode( Token.WHILE, transform(loopNode.getCondition()), transformBlock(loopNode.getBody())); } @Override Node processWithStatement(WithStatement statementNode) { return newNode( Token.WITH, transform(statementNode.getExpression()), transformBlock(statementNode.getStatement())); } @Override Node processIllegalToken(AstNode node) { errorReporter.error( "Unsupported syntax: " + com.google.javascript.jscomp.mozilla.rhino.Token.typeToName( node.getType()), sourceName, node.getLineno(), "", 0); return newNode(Token.EMPTY); }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> case com.google.javascript.jscomp.mozilla.rhino.Token.VOID: return Token.VOID; case com.google.javascript.jscomp.mozilla.rhino.Token.RESERVED: return Token.RESERVED; case com.google.javascript.jscomp.mozilla.rhino.Token.EMPTY: return Token.EMPTY; case com.google.javascript.jscomp.mozilla.rhino.Token.BLOCK: return Token.BLOCK; case com.google.javascript.jscomp.mozilla.rhino.Token.LABEL: return Token.LABEL; case com.google.javascript.jscomp.mozilla.rhino.Token.TARGET: return Token.TARGET; case com.google.javascript.jscomp.mozilla.rhino.Token.LOOP: return Token.LOOP; case com.google.javascript.jscomp.mozilla.rhino.Token.EXPR_VOID: case com.google.javascript.jscomp.mozilla.rhino.Token.EXPR_RESULT: return Token.EXPR_RESULT; case com.google.javascript.jscomp.mozilla.rhino.Token.JSR: return Token.JSR; case com.google.javascript.jscomp.mozilla.rhino.Token.SCRIPT: return Token.SCRIPT; case com.google.javascript.jscomp.mozilla.rhino.Token.TYPEOFNAME: return Token.TYPEOFNAME; case com.google.javascript.jscomp.mozilla.rhino.Token.USE_STACK: return Token.USE_STACK; case com.google.javascript.jscomp.mozilla.rhino.Token.SETPROP_OP: return Token.SETPROP_OP; case com.google.javascript.jscomp.mozilla.rhino.Token.SETELEM_OP: return Token.SETELEM_OP; case com.google.javascript.jscomp.mozilla.rhino.Token.LOCAL_BLOCK: return Token.LOCAL_BLOCK; case com.google.javascript.jscomp.mozilla.rhino.Token.SET_REF_OP: return Token.SET_REF_OP; case com.google.javascript.jscomp.mozilla.rhino.Token.DOTDOT: return Token.DOTDOT; case com.

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import com.google.javascript.rhino.ErrorReporter; /** * Value types (null, void, number, boolean, string). */ abstract class ValueType extends JSType { ValueType(JSTypeRegistry registry) { super(registry); } @Override public boolean isSubtype(JSType that) { return JSType.isSubtype(this, that); } @Override final JS

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>/* * Copyright 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.javascript.jscomp.CheckLevel; /** * Sets the level for a particular DiagnosticGroup. * @author nicksantos@google.com (Nick Santos) */ public class DiagnosticGroupWarningsGuard extends WarningsGuard { private final DiagnosticGroup group; private final CheckLevel level; public DiagnosticGroupWarningsGuard( DiagnosticGroup group, CheckLevel level) { this.group = group; this.level = level; } @Override public CheckLevel level(JSError error) { return group.matches(error) ? level : null; } @Override public boolean disables(DiagnosticGroup otherGroup) { return !level.isOn() && group.isSubGroup(otherGroup); } @Override public boolean enables(DiagnosticGroup otherGroup) { if (level.isOn()) { for (DiagnosticType type : otherGroup.getTypes()) { if (group.matches(type)) { return true; } } } return false; } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>/* * Copyright 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; /** * Annotates nodes with information from their original input file * before the compiler performs work that changes this information (such * as its original location, its original name, etc). * * Information saved: * * - Annotates all nodes with a SOURCEFILE_PROP indicating the input * file from which it was generated. * * - Annotates all NAME nodes with an ORIGINALNAME_PROP indicating its original * name. * * - Annotates all string GET_PROP nodes with an ORIGINALNAME_PROP. * * - Annotates all OBJECT_LITERAL unquoted string key nodes with an * ORIGINALNAME_PROP. * * */ class SourceInformationAnnotator extends NodeTraversal.AbstractPostOrderCallback { private final String sourceFile; private final boolean doSanityChecks; public SourceInformationAnnotator( String sourceFile, boolean doSanityChecks) { this.sourceFile = sourceFile; this.doSanityChecks = doSanityChecks; } @Override public void visit(NodeTraversal t, Node n, Node parent) { // Verify the source file is annotated. if (doSanityChecks && sourceFile != null) { Preconditions.checkState(sourceFile.equals( n.getProp(Node.SOURCEFILE_PROP))); } // Annotate the original name. switch (n.getType

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> roots) { Preconditions.checkArgument(inputs.containsAll(roots)); Set<INPUT> included = Sets.newHashSet(); Deque<INPUT> worklist = new ArrayDeque<INPUT>(roots); while (!worklist.isEmpty()) { INPUT current = worklist.pop(); if (included.add(current)) { for (String req : current.getRequires()) { INPUT dep = provideMap.get(req); if (dep != null) { worklist.add(dep); } } } } ImmutableList.Builder<INPUT> builder = ImmutableList.builder(); for (INPUT current : sortedList) { if (included.contains(current)) { builder.add(current); } } return builder.build(); } public List<INPUT> getInputsWithoutProvides() { return Collections.<INPUT>unmodifiableList(noProvides); } private static <T> List<T> topologicalStableSort( List<T> items, Multimap<T, T> deps) { final Map<T, Integer> originalIndex = Maps.newHashMap(); for (int i = 0; i < items.size(); i++) { originalIndex.put(items.get(i), i); } PriorityQueue<T> inDegreeZero = new PriorityQueue<T>(items.size(), new Comparator<T>() { @Override public int compare(T a, T b) { return originalIndex.get(a).intValue() - originalIndex.get(b).intValue(); } }); List<T> result = Lists.newArrayList(); Multiset<T> inDegree = HashMultiset.create(); Multimap<T, T> reverseDeps = ArrayListMultimap.create(); Multimaps.invertFrom(deps, reverseDeps); // First, add all the inputs with in-degree 0. for (T item : items) { Collection<T> itemDeps = deps.get(item); inDegree.add(item, itemDeps.size()); if (itemDeps.isEmpty()) { inDegreeZero.add(item); } } // Then, iterate to a fixed point over the reverse dependency graph. while (!inDegreeZero.isEmpty()) { T item = inDegreeZero

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>Prototype; } else if (implicitPrototype == null) { this.implicitPrototype = registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE); } else { this.implicitPrototype = implicitPrototype; } } /** * Gets the number of properties of this object. */ @Override public int getPropertiesCount() { ObjectType implicitPrototype = getImplicitPrototype(); if (implicitPrototype == null) { return this.properties.size(); } int localCount = 0; for (String property : properties.keySet()) { if (!implicitPrototype.hasProperty(property)) { localCount++; } } return implicitPrototype.getPropertiesCount() + localCount; } @Override public boolean hasProperty(String propertyName) { if (properties.get(propertyName) != null) { return true; } ObjectType implicitPrototype = getImplicitPrototype(); if (implicitPrototype != null) { return implicitPrototype.hasProperty(propertyName); } return false; } @Override public boolean hasOwnProperty(String propertyName) { return properties.get(propertyName) != null; } @Override public Set<String> getOwnPropertyNames() { return properties.keySet(); } @Override public boolean isPropertyTypeDeclared(String property) { Property p = properties.get(property); if (p == null) { ObjectType implicitPrototype = getImplicitPrototype(); if (implicitPrototype != null) { return implicitPrototype.isPropertyTypeDeclared(property); } // property does not exist return false; } return !p.inferred; } @Override void collectPropertyNames(Set<String> props) { for (String prop : properties.keySet()) { props.add(prop); } ObjectType implicitPrototype = getImplicitPrototype(); if (implicitPrototype != null) { implicitPrototype.collectPropertyNames(props); } } @Override public boolean isPropertyTypeInferred(String property) { Property p = properties.get(property); if (p == null) { ObjectType implicitPrototype = getImplicitPrototype(); if (implicitPrototype != null) { return implicitPrototype.isPropertyTypeInferred(property); } // property does not exist return false; } return p.in

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>ferred; } @Override public JSType getPropertyType(String propertyName) { Property p = properties.get(propertyName); if (p != null) { return p.type; } ObjectType implicitPrototype = getImplicitPrototype(); if (implicitPrototype != null) { return implicitPrototype.getPropertyType(propertyName); } return getNativeType(JSTypeNative.UNKNOWN_TYPE); } @Override public boolean isPropertyInExterns(String propertyName) { Property p = properties.get(propertyName); if (p != null) { return p.inExterns; } ObjectType implicitPrototype = getImplicitPrototype(); if (implicitPrototype != null) { return implicitPrototype.isPropertyInExterns(propertyName); } return false; } @Override boolean defineProperty(String name, JSType type, boolean inferred, boolean inExterns) { if (hasOwnDeclaredProperty(name)) { return false; } properties.put(name, new Property(type, inferred, inExterns)); return true; } @Override public JSDocInfo getOwnPropertyJSDocInfo(String propertyName) { Property p = properties.get(propertyName); if (p != null) { return p.docInfo; } return null; } @Override public void setPropertyJSDocInfo(String propertyName, JSDocInfo info, boolean inExterns) { if (info != null) { if (!properties.containsKey(propertyName)) { // If docInfo was attached, but the type of the property // was not defined anywhere, then we consider this an explicit // declaration of the property. defineInferredProperty(propertyName, getPropertyType(propertyName), inExterns); } // The prototype property is not represented as a normal Property. // We probably don't want to attach any JSDoc to it anyway. Property property = properties.get(propertyName); if (property != null) { property.docInfo = info; } } } @Override public boolean matchesNumberContext() { return isNumberObjectType() || isDateType() || isBooleanObjectType() || isStringObjectType() || hasOverridenNativeProperty("valueOf"); } @

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>Override public boolean matchesStringContext() { return isTheObjectType() || isStringObjectType() || isDateType() || isRegexpType() || isArrayType() || isNumberObjectType() || isBooleanObjectType() || hasOverridenNativeProperty("toString"); } /** * Given the name of a native object property, checks whether the property is * present on the object and different from the native one. */ private boolean hasOverridenNativeProperty(String propertyName) { if (isNative()) { return false; } JSType propertyType = getPropertyType(propertyName); ObjectType nativeType = this.isFunctionType() ? registry.getNativeObjectType(JSTypeNative.FUNCTION_PROTOTYPE) : registry.getNativeObjectType(JSTypeNative.OBJECT_PROTOTYPE); JSType nativePropertyType = nativeType.getPropertyType(propertyName); return propertyType != nativePropertyType; } @Override public JSType unboxesTo() { if (isStringObjectType()) { return getNativeType(JSTypeNative.STRING_TYPE); } else if (isBooleanObjectType()) { return getNativeType(JSTypeNative.BOOLEAN_TYPE); } else if (isNumberObjectType()) { return getNativeType(JSTypeNative.NUMBER_TYPE); } else { return super.unboxesTo(); } } @Override public boolean matchesObjectContext() { return true; } @Override public boolean canBeCalled() { return isRegexpType(); } /** * Whether this represents a native type (such as Object, Date, * RegExp, etc.). */ boolean isNative() { return nativeType; } @Override public String toString() { if (hasReferenceName()) { return getReferenceName(); } else if (prettyPrint) { // Use a tree set so that the properties are sorted. Set<String> propertyNames = Sets.newTreeSet(); for (ObjectType current = this; current != null && !current.isNativeObjectType() && propertyNames.size() <= MAX_PRETTY_PRINTED_PROPERTIES; current = current.getImplicitPrototype()) { propertyNames.addAll(current.getOwnPropertyNames()); } StringBuilder sb = new StringBuilder(); sb.append("{"); int i = 0

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>; for (String property : propertyNames) { if (i > 0) { sb.append(", "); } sb.append(property); sb.append(": "); sb.append(getPropertyType(property).toString()); ++i; if (i == MAX_PRETTY_PRINTED_PROPERTIES) { sb.append(", ..."); break; } } sb.append("}"); return sb.toString(); } else { return "{...}"; } } void setPrettyPrint(boolean prettyPrint) { this.prettyPrint = prettyPrint; } @Override public FunctionType getConstructor() { return null; } @Override public ObjectType getImplicitPrototype() { return implicitPrototype; } /** * This should only be reset on the FunctionPrototypeType, only to fix an * incorrectly established prototype chain due to the user having a mismatch * in super class declaration, and only before properties on that type are * processed. */ void setImplicitPrototype(ObjectType implicitPrototype) { checkState(!hasCachedValues()); this.implicitPrototype = implicitPrototype; } @Override public String getReferenceName() { if (className != null) { return className; } else { return null; } } @Override public boolean hasReferenceName() { return className != null; } @Override public boolean isSubtype(JSType that) { if (JSType.isSubtype(this, that)) { return true; } // Union types if (that instanceof UnionType) { // The static {@code JSType.isSubtype} check already decomposed // union types, so we don't need to check those again. return false; } // record types if (that instanceof RecordType) { return RecordType.isSubtype(this, (RecordType) that); } // Interfaces // Find all the interfaces implemented by this class and compare each one // to the interface instance. ObjectType thatObj = that.toObjectType(); ObjectType thatCtor = thatObj == null ? null : thatObj.getConstructor(); if (thatCtor != null && thatCtor.isInterface()) { Iterable<ObjectType> thisInterfaces = getCtorImplementedInterfaces(); for (ObjectType thisInterface : this

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>Interfaces) { if (thisInterface.isSubtype(that)) { return true; } } } // other prototype based objects if (that != null) { if (isUnknownType() || implicitPrototypeChainIsUnknown()) { // If unsure, say 'yes', to avoid spurious warnings. // TODO(user): resolve the prototype chain completely in all cases, // to avoid guessing. return true; } return this.isImplicitPrototype(thatObj); } return false; } private boolean implicitPrototypeChainIsUnknown() { ObjectType p = getImplicitPrototype(); while (p != null) { if (p.isUnknownType()) { return true; } p = p.getImplicitPrototype(); } return false; } private static final class Property implements Serializable { private static final long serialVersionUID = 1L; /** * Property's type. */ private JSType type; /** * Whether the property's type is inferred. */ private final boolean inferred; /** * Whether the property is defined in the externs. */ private final boolean inExterns; /** The JSDocInfo for this property. */ private JSDocInfo docInfo = null; private Property(JSType type, boolean inferred, boolean inExterns) { this.type = type; this.inferred = inferred; this.inExterns = inExterns; } } @Override public boolean hasCachedValues() { return super.hasCachedValues(); } /** Whether this is a built-in object. */ @Override public boolean isNativeObjectType() { return nativeType; } @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) { setResolvedTypeInternal(this); // Don't try to resolve native types, because it's unnecessary and // there are infinite loops between native types. if (implicitPrototype != null && !implicitPrototype.isNativeObjectType()) { implicitPrototype = (ObjectType) implicitPrototype.resolve(t, scope); } for (Property prop : properties.values()) { prop.type = safeResolve(prop.type, t, scope); } return this; } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> wanted since he or she probably meant to use their // own PassConfig object. Preconditions.checkNotNull(passes); if (this.passes != null) { throw new IllegalStateException("this.passes has already been assigned"); } this.passes = passes; } /** * Carry out any special checks or procedures that need to be done before * proceeding with rest of the compilation process. * * @return true, to continue with compilation */ boolean precheck() { return true; } public void check() { runCustomPasses(CustomPassExecutionTime.BEFORE_CHECKS); PhaseOptimizer phaseOptimizer = new PhaseOptimizer(this, tracker); if (options.devMode == DevMode.EVERY_PASS) { phaseOptimizer.setSanityCheck(sanityCheck); } phaseOptimizer.consume(getPassConfig().getChecks()); phaseOptimizer.process(externsRoot, jsRoot); if (hasErrors()) { return; } // TODO(nicksantos): clean this up. The flow here is too hard to follow. if (options.nameAnonymousFunctionsOnly) { return; } if (options.removeTryCatchFinally) { removeTryCatchFinally(); } if (!options.stripTypes.isEmpty() || !options.stripNameSuffixes.isEmpty() || !options.stripTypePrefixes.isEmpty() || !options.stripNamePrefixes.isEmpty()) { stripCode(options.stripTypes, options.stripNameSuffixes, options.stripTypePrefixes, options.stripNamePrefixes); } runCustomPasses(CustomPassExecutionTime.BEFORE_OPTIMIZATIONS); } private void externExports() { logger.info("Creating extern file for exports"); startPass("externExports"); ExternExportsPass pass = new ExternExportsPass(this); process(pass); externExports = pass.getGeneratedExterns(); endPass(); } void process(CompilerPass p) { p.process(externsRoot, jsRoot); } private final PassFactory sanityCheck = new PassFactory("sanityCheck", false) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new SanityCheck(compiler); } }; private void maybeSan

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> currentTracer = null; maybeSanityCheck(); } /** * Returns a new tracer for the given pass name. */ Tracer newTracer(String passName) { String comment = passName + (recentChange.hasCodeChanged() ? " on recently changed AST" : ""); if (options.tracer.isOn()) { tracker.recordPassStart(passName); } return new Tracer("Compiler", comment); } void stopTracer(Tracer t, String passName) { long result = t.stop(); if (options.tracer.isOn()) { tracker.recordPassStop(passName, result); } } /** * Returns the result of the compilation. */ public Result getResult() { PassConfig.State state = getPassConfig().getIntermediateState(); return new Result(getErrors(), getWarnings(), debugLog.toString(), state.variableMap, state.propertyMap, state.anonymousFunctionNameMap, state.stringMap, functionInformationMap, sourceMap, externExports, state.cssNames); } /** * Returns an array constructed from errors + temporary warnings. */ public JSError[] getMessages() { return getErrors(); } /** * Returns the array of errors (never null). */ public JSError[] getErrors() { return errorManager.getErrors(); } /** * Returns the array of warnings (never null). */ public JSError[] getWarnings() { return errorManager.getWarnings(); } /** * Returns the root node of the AST, which includes both externs and source. */ public Node getRoot() { return externAndJsRoot; } /** * Creates a new id for making unique names. */ private int nextUniqueNameId() { return uniqueNameId++; } /** * Resets the unique name id counter */ @VisibleForTesting void resetUniqueNameId() { uniqueNameId = 0; } @Override Supplier<String> getUniqueNameIdSupplier() { final Compiler self = this; return new Supplier<String>() { public String get() { return String.valueOf(self.nextUniqueNameId()); } }; } /** * Set if the normalization

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> pass has been done. * Note: non-private to enable test cases that require the Normalize pass. */ @Override void setNormalized() { normalized = true; } /** * Set once unnormalizing passes have been start. * Note: non-private to enable test cases that require the Normalize pass. */ @Override void setUnnormalized() { normalized = false; } @Override boolean isNormalized() { return normalized; } @Override boolean areNodesEqualForInlining(Node n1, Node n2) { if (options.ambiguateProperties || options.disambiguateProperties) { // The type based optimizations require that type information is preserved // during other optimizations. return n1.checkTreeTypeAwareEqualsSilent(n2); } else { return n1.checkTreeEqualsSilent(n2); } } //------------------------------------------------------------------------ // Inputs //------------------------------------------------------------------------ // TODO(nicksantos): Decide which parts of these belong in an AbstractCompiler // interface, and which ones should always be injected. @Override public CompilerInput getInput(String name) { return inputsByName.get(name); } @Override public CompilerInput newExternInput(String name) { if (inputsByName.containsKey(name)) { throw new IllegalArgumentException("Conflicting externs name: " + name); } SourceAst ast = new SyntheticAst(name); CompilerInput input = new CompilerInput(ast, name, true); inputsByName.put(name, input); externsRoot.addChildToFront(ast.getAstRoot(this)); return input; } /** Add a source input dynamically. Intended for incremental compilation. */ void addIncrementalSourceAst(JsAst ast) { String sourceName = ast.getSourceFile().getName(); Preconditions.checkState( getInput(sourceName) == null, "Duplicate input of name " + sourceName); inputsByName.put(sourceName, new CompilerInput(ast)); } @Override JSModuleGraph getModuleGraph() { return moduleGraph; } @Override public JSTypeRegistry getTypeRegistry() { if (typeRegistry == null) { typeRegistry = new JSTypeRegistry(oldErrorReporter,

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> options.looseTypes); } return typeRegistry; } @Override ScopeCreator getScopeCreator() { return getPassConfig().getScopeCreator(); } @Override public Scope getTopScope() { return getPassConfig().getTopScope(); } @Override public ReverseAbstractInterpreter getReverseAbstractInterpreter() { if (abstractInterpreter == null) { ChainableReverseAbstractInterpreter interpreter = new SemanticReverseAbstractInterpreter( getCodingConvention(), getTypeRegistry()); if (options.closurePass) { interpreter = new ClosureReverseAbstractInterpreter( getCodingConvention(), getTypeRegistry()) .append(interpreter).getFirst(); } abstractInterpreter = interpreter; } return abstractInterpreter; } @Override TypeValidator getTypeValidator() { if (typeValidator == null) { typeValidator = new TypeValidator(this); } return typeValidator; } //------------------------------------------------------------------------ // Parsing //------------------------------------------------------------------------ /** * Parses the externs and main inputs. * * @return A synthetic root node whose two children are the externs root * and the main root */ Node parseInputs() { boolean devMode = options.devMode != DevMode.OFF; // If old roots exist (we are parsing a second time), detach each of the // individual file parse trees. if (externsRoot != null) { externsRoot.detachChildren(); } if (jsRoot != null) { jsRoot.detachChildren(); } // Parse main js sources. jsRoot = new Node(Token.BLOCK); jsRoot.setIsSyntheticBlock(true); if (options.tracer.isOn()) { tracker = new PerformanceTracker(jsRoot, options.tracer == TracerMode.ALL); addChangeHandler(tracker.getCodeChangeHandler()); } Tracer tracer = newTracer("parseInputs"); try { // Parse externs sources. externsRoot = new Node(Token.BLOCK); externsRoot.setIsSyntheticBlock(true); for (CompilerInput input : externs) { Node n = input.getAstRoot(this); if (hasErrors()) { return null; } externsRoot.addChildToBack(n); } // Check if the sources need to be re-ordered

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>ate the nodes in the tree with information from the // input file. This information is used to construct the SourceMap. SourceInformationAnnotator sia = new SourceInformationAnnotator( input.getName(), options.devMode != DevMode.OFF); NodeTraversal.traverse(this, n, sia); } jsRoot.addChildToBack(n); } externAndJsRoot = new Node(Token.BLOCK, externsRoot, jsRoot); externAndJsRoot.setIsSyntheticBlock(true); return externAndJsRoot; } finally { stopTracer(tracer, "parseInputs"); } } public Node parse(JSSourceFile file) { initCompilerOptionsIfTesting(); addToDebugLog("Parsing: " + file.getName()); return new JsAst(file).getAstRoot(this); } @Override Node parseSyntheticCode(String js) { CompilerInput input = new CompilerInput( JSSourceFile.fromCode(" [synthetic] ", js)); inputsByName.put(input.getName(), input); return input.getAstRoot(this); } void initCompilerOptionsIfTesting() { if (options == null) { // initialization for tests that don't initialize the compiler // by the normal mechanisms. initOptions(new CompilerOptions()); } } @Override Node parseSyntheticCode(String fileName, String js) { initCompilerOptionsIfTesting(); return parse(JSSourceFile.fromCode(fileName, js)); } Node parseTestCode(String js) { initCompilerOptionsIfTesting(); CompilerInput input = new CompilerInput( JSSourceFile.fromCode(" [testcode] ", js)); if (inputsByName == null) { inputsByName = Maps.newHashMap(); } inputsByName.put(input.getName(), input); return input.getAstRoot(this); } @Override ErrorReporter getDefaultErrorReporter() { return defaultErrorReporter; } //------------------------------------------------------------------------ // Convert back to source code //------------------------------------------------------------------------ /** * Converts the main parse tree back to js code. */ public String toSource() { return runInCompilerThread(new Callable<String>() { public String call() throws Exception { Tracer tracer =

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>\n") .append(root.getJSDocInfo().getLicense()) .append("*/\n"); } // If there is a valid source map, then indicate to it that the current // root node's mappings are offset by the given string builder buffer. if (options.sourceMapOutputPath != null) { sourceMap.setStartingPosition( cb.getLineIndex(), cb.getColumnIndex()); } String code = toSource(root, sourceMap); if (!code.isEmpty()) { cb.append(code); if (!code.endsWith(";")) { cb.append(";"); } } return null; } }); } /** * Generates JavaScript source code for an AST, doesn't generate source * map info. */ @Override String toSource(Node n) { initCompilerOptionsIfTesting(); return toSource(n, null); } /** * Generates JavaScript source code for an AST. */ private String toSource(Node n, SourceMap sourceMap) { CodePrinter.Builder builder = new CodePrinter.Builder(n); builder.setPrettyPrint(options.prettyPrint); builder.setLineBreak(options.lineBreak); builder.setSourceMap(sourceMap); builder.setOutputCharset(options.outputCharset); return builder.build(); } /** * Stores a buffer of text to which more can be appended. This is just like a * StringBuilder except that we also track the number of lines. */ public static class CodeBuilder { private final StringBuilder sb = new StringBuilder(); private int lineCount = 0; /** Removes all text, but leaves the line count unchanged. */ void reset() { sb.setLength(0); } /** Appends the given string to the text buffer. */ CodeBuilder append(String str) { sb.append(str); // Move the line count to the end of the new text. int index = -1; while ((index = str.indexOf('\n', index + 1)) >= 0) { ++lineCount; } return this; } /** Returns all text in the text buffer. */ @Override public String toString() { return sb.toString(); } /** Returns the length of the

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> text buffer. */ public int getLength() { return sb.length(); } /** Returns the (zero-based) index of the last line in the text buffer. */ int getLineIndex() { return lineCount; } /** Returns the (zero-based) index of the last column in the text buffer. */ int getColumnIndex() { int index = sb.lastIndexOf("\n"); return (index >= 0) ? sb.length() - (index + 1) : sb.length(); } /** Determines whether the text ends with the given suffix. */ boolean endsWith(String suffix) { return (sb.length() > suffix.length()) && suffix.equals(sb.substring(sb.length() - suffix.length())); } } //------------------------------------------------------------------------ // Optimizations //------------------------------------------------------------------------ public void optimize() { // Ideally, this pass should be the first pass run, however: // 1) VariableReferenceCheck reports unexpected warnings if Normalize // is done first. // 2) ReplaceMessages, stripCode, and potentially custom passes rely on // unmodified local names. normalize(); PhaseOptimizer phaseOptimizer = new PhaseOptimizer(this, tracker); if (options.devMode == DevMode.EVERY_PASS) { phaseOptimizer.setSanityCheck(sanityCheck); } phaseOptimizer.consume(getPassConfig().getOptimizations()); phaseOptimizer.process(externsRoot, jsRoot); if (hasErrors()) { return; } } @Override void setCssRenamingMap(CssRenamingMap map) { options.cssRenamingMap = map; } @Override CssRenamingMap getCssRenamingMap() { return options.cssRenamingMap; } /** * Reprocesses the current defines over the AST. This is used by GwtCompiler * to generate N outputs for different targets from the same (checked) AST. * For each target, we apply the target-specific defines by calling * {@code processDefines} and then {@code optimize} to optimize the AST * specifically for that target. */ public void processDefines() { (new DefaultPassConfig(options)).processDefines.create(this) .process(externsRoot, jsRoot

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>); } boolean isInliningForbidden() { return options.propertyRenaming == PropertyRenamingPolicy.HEURISTIC || options.propertyRenaming == PropertyRenamingPolicy.AGGRESSIVE_HEURISTIC; } /** Control Flow Analysis. */ ControlFlowGraph<Node> computeCFG() { logger.info("Computing Control Flow Graph"); Tracer tracer = newTracer("computeCFG"); ControlFlowAnalysis cfa = new ControlFlowAnalysis(this, true); process(cfa); stopTracer(tracer, "computeCFG"); return cfa.getCfg(); } public void normalize() { logger.info("Normalizing"); startPass("normalize"); process(new Normalize(this, false)); endPass(); } @Override void prepareAst(Node root) { Tracer tracer = newTracer("prepareAst"); CompilerPass pass = new PrepareAst(this); pass.process(null, root); stopTracer(tracer, "prepareAst"); } void recordFunctionInformation() { logger.info("Recording function information"); startPass("recordFunctionInformation"); RecordFunctionInformation recordFunctionInfoPass = new RecordFunctionInformation( this, getPassConfig().getIntermediateState().functionNames); process(recordFunctionInfoPass); functionInformationMap = recordFunctionInfoPass.getMap(); endPass(); } protected final CodeChangeHandler.RecentChange recentChange = new CodeChangeHandler.RecentChange(); private final List<CodeChangeHandler> codeChangeHandlers = Lists.<CodeChangeHandler>newArrayList(); @Override void addChangeHandler(CodeChangeHandler handler) { codeChangeHandlers.add(handler); } @Override void removeChangeHandler(CodeChangeHandler handler) { codeChangeHandlers.remove(handler); } /** * All passes should call reportCodeChange() when they alter * the JS tree structure. This is verified by CompilerTestCase. * This allows us to optimize to a fixed point. */ @Override public void reportCodeChange() { for (CodeChangeHandler handler : codeChangeHandlers) { handler.reportChange(); } } @Override public CodingConvention getCodingConvention() { CodingConvention convention = options.getCodingConvention(); convention = convention != null ? convention : defaultCodingConvention

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>; return convention; } @Override public boolean isIdeMode() { return options.ideMode; } @Override Config getParserConfig() { if (parserConfig == null) { parserConfig = ParserRunner.createConfig(isIdeMode()); } return parserConfig; } @Override public boolean isTypeCheckingEnabled() { return options.checkTypes; } //------------------------------------------------------------------------ // Error reporting //------------------------------------------------------------------------ @Override public void report(JSError error) { CheckLevel level = error.level; WarningsGuard guard = options.getWarningsGuard(); if (guard != null) { CheckLevel newLevel = guard.level(error); if (newLevel != null) { level = newLevel; } } if (level.isOn()) { errorManager.report(level, error); } } @Override public CheckLevel getErrorLevel(JSError error) { Preconditions.checkNotNull(options); WarningsGuard guards = options.getWarningsGuard(); if (guards == null) { return error.level; } else { return guards.level(error); } } /** * Report an internal error. */ @Override void throwInternalError(String message, Exception cause) { String finalMessage = "INTERNAL COMPILER ERROR.\n" + "Please report this problem.\n" + message; RuntimeException e = new RuntimeException(finalMessage, cause); if (cause != null) { e.setStackTrace(cause.getStackTrace()); } throw e; } /** * Gets the number of errors. */ public int getErrorCount() { return errorManager.getErrorCount(); } /** * Gets the number of warnings. */ public int getWarningCount() { return errorManager.getWarningCount(); } @Override boolean hasHaltingErrors() { return !isIdeMode() && getErrorCount() > 0; } /** * Consults the {@link ErrorManager} to see if we've encountered errors * that should halt compilation. <p> * * If {@link CompilerOptions#ideMode} is {@code true}, this function * always returns {@code false} without consulting

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> the error manager. The * error manager will continue to be told about new errors and warnings, but * the compiler will complete compilation of all inputs.<p> */ public boolean hasErrors() { return hasHaltingErrors(); } /** Called from the compiler passes, adds debug info */ @Override void addToDebugLog(String str) { debugLog.append(str); debugLog.append('\n'); logger.fine(str); } private SourceFile getSourceFileByName(String sourceName) { if (inputsByName.containsKey(sourceName)) { return inputsByName.get(sourceName).getSourceFile(); } return null; } public String getSourceLine(String sourceName, int lineNumber) { if (lineNumber < 1) { return null; } SourceFile input = getSourceFileByName(sourceName); if (input != null) { return input.getLine(lineNumber); } return null; } public Region getSourceRegion(String sourceName, int lineNumber) { if (lineNumber < 1) { return null; } SourceFile input = getSourceFileByName(sourceName); if (input != null) { return input.getRegion(lineNumber); } return null; } //------------------------------------------------------------------------ // Package-private helpers //------------------------------------------------------------------------ @Override Node getNodeForCodeInsertion(JSModule module) { if (module == null) { if (inputs.isEmpty()) { throw new IllegalStateException("No inputs"); } return inputs.get(0).getAstRoot(this); } List<CompilerInput> moduleInputs = module.getInputs(); if (moduleInputs.size() > 0) { return moduleInputs.get(0).getAstRoot(this); } throw new IllegalStateException("Root module has no inputs"); } public SourceMap getSourceMap() { return sourceMap; } VariableMap getVariableMap() { return getPassConfig().getIntermediateState().variableMap; } VariableMap getPropertyMap() { return getPassConfig().getIntermediateState().propertyMap; } CompilerOptions getOptions() { return options; } FunctionInformationMap getFunctionalInformationMap() { return functionInformationMap; } /** *

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> Sets the logging level for the com.google.javascript.jscomp package. */ public static void setLoggingLevel(Level level) { logger.setLevel(level); } /** Gets the DOT graph of the AST generated at the end of compilation. */ public String getAstDotGraph() throws IOException { if (jsRoot != null) { ControlFlowAnalysis cfa = new ControlFlowAnalysis(this, true); cfa.process(null, jsRoot); return DotFormatter.toDot(jsRoot, cfa.getCfg()); } else { return ""; } } @Override public ErrorManager getErrorManager() { if (options == null) { initOptions(new CompilerOptions()); } return errorManager; } @Override List<CompilerInput> getInputsInOrder() { return Collections.<CompilerInput>unmodifiableList(inputs); } /** * Stores the internal compiler state just before optimization is performed. * This can be saved and restored in order to efficiently optimize multiple * different output targets without having to perform checking multiple times. * * NOTE: This does not include all parts of the compiler's internal state. In * particular, JSSourceFiles and CompilerOptions are not recorded. In * order to recreate a Compiler instance from scratch, you would need to * call {@code init} with the same arguments as in the initial creation before * restoring intermediate state. */ public static class IntermediateState implements Serializable { private static final long serialVersionUID = 1L; Node externsRoot; private Node jsRoot; private List<CompilerInput> externs; private List<CompilerInput> inputs; private List<JSModule> modules; private PassConfig.State passConfigState; private JSTypeRegistry typeRegistry; private boolean normalized; private IntermediateState() {} } /** * Returns the current internal state, excluding the input files and modules. */ public IntermediateState getState() { IntermediateState state = new IntermediateState(); state.externsRoot = externsRoot; state.jsRoot = jsRoot; state.externs = externs; state.inputs = inputs; state.modules = modules; state.passConfigState = getPassConfig().getIntermediateState(); state.type

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>Registry = typeRegistry; state.normalized = normalized; return state; } /** * Sets the internal state to the capture given. Note that this assumes that * the input files are already set up. */ public void setState(IntermediateState state) { externsRoot = state.externsRoot; jsRoot = state.jsRoot; externs = state.externs; inputs = state.inputs; modules = state.modules; passes = createPassConfigInternal(); getPassConfig().setIntermediateState(state.passConfigState); typeRegistry = state.typeRegistry; normalized = state.normalized; } @VisibleForTesting List<CompilerInput> getInputsForTesting() { return inputs; } @VisibleForTesting List<CompilerInput> getExternsForTesting() { return externs; } @Override boolean hasRegExpGlobalReferences() { return hasRegExpGlobalReferences; } @Override void setHasRegExpGlobalReferences(boolean references) { hasRegExpGlobalReferences = references; } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>/* * Copyright 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.javascript.jscomp.parsing.ParserRunner; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import java.io.IOException; import java.util.logging.Logger; /** * Generates an AST for a JavaScript source file. * * */ public class JsAst implements SourceAst { private static final Logger logger_ = Logger.getLogger(JsAst.class.getName()); private static final long serialVersionUID = 1L; private transient SourceFile sourceFile; private String fileName; private Node root; public JsAst(SourceFile sourceFile) { this.sourceFile = sourceFile; this.fileName = sourceFile.getName(); } @Override public Node getAstRoot(AbstractCompiler compiler) { if (root == null) { createAst(compiler); } return root; } @Override public void clearAst() { root = null; // While we're at it, clear out any saved text in the source file on // the assumption that if we're dumping the parse tree, then we probably // assume regenerating everything else is a smart idea also. sourceFile.clearCachedSource(); } @Override public SourceFile getSourceFile() { return sourceFile; } @Override public void setSourceFile(SourceFile file) { Preconditions.checkState(fileName.equals(file.getName())); sourceFile = file; } private void createAst(AbstractCompiler compiler)

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>/* * Copyright 2007 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; /** * A source excerpt provider is responsible for building source code excerpt * of specific locations, such as a specific line or a region around a * given line number. * * */ public interface SourceExcerptProvider { /** * Source excerpt variety. */ enum SourceExcerpt { /** * Line excerpt. */ LINE { @Override public String get(SourceExcerptProvider source, String sourceName, int lineNumber, ExcerptFormatter formatter) { return formatter.formatLine( source.getSourceLine(sourceName, lineNumber), lineNumber); } }, /** * Region excerpt. */ REGION { @Override public String get(SourceExcerptProvider source, String sourceName, int lineNumber, ExcerptFormatter formatter) { return formatter.formatRegion( source.getSourceRegion(sourceName, lineNumber)); } }; /** * Get a source excerpt string based on the type of the source excerpt. */ public abstract String get(SourceExcerptProvider source, String sourceName, int lineNumber, ExcerptFormatter formatter); } /** * Get the line indicated by the line number. This call will return only the * specific line. * * @param lineNumber the line number, 1 being the first line of the file * @return the line indicated, or {@code null} if it does not exist */ String getSourceLine(String sourceName, int lineNumber); /** * Get a region around the indicated line number. The exact definition of a * region is implementation specific, but it must

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>details); } @Override public final String getMessage() { String details = details(); if (sourceName == null || lineNumber <= 0) { return details; } StringBuilder buf = new StringBuilder(details); buf.append(" ("); if (sourceName != null) { buf.append(sourceName); } if (lineNumber > 0) { buf.append('#'); buf.append(lineNumber); } buf.append(')'); return buf.toString(); } public String details() { return super.getMessage(); } /** * Get the uri of the script source containing the error, or null * if that information is not available. */ public final String sourceName() { return sourceName; } /** * Initialize the uri of the script source containing the error. * * @param sourceName the uri of the script source reponsible for the error. * It should not be <tt>null</tt>. * * @throws IllegalStateException if the method is called more then once. */ public final void initSourceName(String sourceName) { if (sourceName == null) throw new IllegalArgumentException(); if (this.sourceName != null) throw new IllegalStateException(); this.sourceName = sourceName; } /** * Returns the line number of the statement causing the error, * or zero if not available. */ public final int lineNumber() { return lineNumber; } /** * Initialize the line number of the script statement causing the error. * * @param lineNumber the line number in the script source. * It should be positive number. * * @throws IllegalStateException if the method is called more then once. */ public final void initLineNumber(int lineNumber) { if (lineNumber <= 0) throw new IllegalArgumentException(String.valueOf(lineNumber)); if (this.lineNumber > 0) throw new IllegalStateException(); this.lineNumber = lineNumber; } /** * The column number of the location of the error, or zero if unknown. */ public final int columnNumber() { return columnNumber; } /** * Initialize the column number of the script statement causing the error. * * @param columnNumber the

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> { return name.endsWith(".js"); } }); } /** * Get a string representing the script stack of this exception. * If optimization is enabled, this corresponds to all java stack elements * with a source name matching the <code>filter</code>. * @param filter the file name filter to determine whether a file is a * script file * @return a script stack dump * @since 1.6R6 */ public String getScriptStackTrace(FilenameFilter filter) { // The real Rhino code here has been removed. return "<No stack trace available>"; } @Override public void printStackTrace(PrintWriter s) { if (interpreterStackInfo == null) { super.printStackTrace(s); } else { s.print(generateStackTrace()); } } @Override public void printStackTrace(PrintStream s) { if (interpreterStackInfo == null) { super.printStackTrace(s); } else { s.print(generateStackTrace()); } } private String sourceName; private int lineNumber; private String lineSource; private int columnNumber; Object interpreterStackInfo; int[] interpreterLineData; }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> import java.util.Set; /** * Object type. * * In JavaScript, all object types have properties, and each of those * properties has a type. Property types may be DECLARED, INFERRED, or * UNKNOWN. * * DECLARED properties have an explicit type annotation, as in: * <code> * /xx @type {number} x/ * Foo.prototype.bar = 1; * </code> * This property may only hold number values, and an assignment to any * other type of value is an error. * * INFERRED properties do not have an explicit type annotation. Rather, * we try to find all the possible types that this property can hold. * <code> * Foo.prototype.bar = 1; * </code> * If the programmer assigns other types of values to this property, * the property will take on the union of all these types. * * UNKNOWN properties are properties on the UNKNOWN type. The UNKNOWN * type has all properties, but we do not know whether they are * declared or inferred. * * */ public abstract class ObjectType extends JSType { private boolean visited; private JSDocInfo docInfo = null; private boolean unknown = true; ObjectType(JSTypeRegistry registry) { super(registry); } /** * Gets the declared default element type. * @see ParameterizedType */ public JSType getParameterType() { return null; } /** * Gets the declared default index type. * @see IndexedType */ public JSType getIndexType() { return null; } /** * Gets the docInfo for this type. */ @Override public JSDocInfo getJSDocInfo() { if (docInfo != null) { return docInfo; } else if (getImplicitPrototype() != null) { return getImplicitPrototype().getJSDocInfo(); } else { return super.getJSDocInfo(); } } /** * Sets the docInfo for this type from the given * {@link JSDocInfo}. The {@code JSDocInfo} may be {@code null}. */ public void setJSDocInfo(JSDocInfo info

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>) { docInfo = info; } /** * Detects a cycle in the implicit prototype chain. This method accesses * the {@link #getImplicitPrototype()} method and must therefore be * invoked only after the object is sufficiently initialized to respond to * calls to this method.<p> * * The method is not thread safe.<p> * * @return True iff an implicit prototype cycle was detected. */ final boolean detectImplicitPrototypeCycle() { // detecting cycle this.visited = true; ObjectType p = getImplicitPrototype(); while (p != null) { if (p.visited) { return true; } else { p.visited = true; } p = p.getImplicitPrototype(); } // clean up p = this; do { p.visited = false; p = p.getImplicitPrototype(); } while (p != null); return false; } /** * Gets the reference name for this object. This includes named types * like constructors, prototypes, and enums. It notably does not include * literal types like strings and booleans and structural types. * @return the object's name or {@code null} if this is an anonymous * object */ public abstract String getReferenceName(); /** * Returns true if the object is named. * @return true if the object is named, false if it is anonymous */ public boolean hasReferenceName() { return false; } @Override public TernaryValue testForEquality(JSType that) { // super TernaryValue result = super.testForEquality(that); if (result != null) { return result; } // objects are comparable to everything but null/undefined if (that.isSubtype( getNativeType(JSTypeNative.OBJECT_NUMBER_STRING_BOOLEAN))) { return UNKNOWN; } else { return FALSE; } } /** * Gets this object's constructor. * @return this object's constructor or {@code null} if it is a native * object (constructed natively v.s. by instantiation of a function) */ public abstract FunctionType getConstructor(); /** * Gets the implicit prototype (a.k.a. the {@code [[

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> called, so setting this incorrectly could result * in live code being removed. * @return True if the property was registered successfully, false if this * conflicts with a previous property type declaration. */ abstract boolean defineProperty(String propertyName, JSType type, boolean inferred, boolean inExterns); /** * Gets the docInfo on the specified property on this type. This should not * be done implemented recursively, as you generally need to know exactly on * which type in the prototype chain the JSDocInfo exists. */ public JSDocInfo getOwnPropertyJSDocInfo(String propertyName) { return null; } /** * Sets the docInfo for the specified property from the * {@link JSDocInfo} on its definition. * @param info {@code JSDocInfo} for the property definition. May be * {@code null}. * @param inExterns {@code true} if this property was defined in an externs * file. TightenTypes assumes that any function passed to an externs * property could be called, so setting this incorrectly could result * in live code being removed. */ public void setPropertyJSDocInfo(String propertyName, JSDocInfo info, boolean inExterns) { // by default, do nothing } @Override public JSType findPropertyType(String propertyName) { return hasProperty(propertyName) ? getPropertyType(propertyName) : null; } /** * Gets the property type of the property whose name is given. If the * underlying object does not have this property, the Unknown type is * returned to indicate that no information is available on this property. * * @return the property's type or {@link UnknownType}. This method never * returns {@code null}. */ public abstract JSType getPropertyType(String propertyName); /** * Checks whether the property whose name is given is present on the * object. */ public abstract boolean hasProperty(String propertyName); /** * Checks whether the property whose name is given is present directly on * the object. Returns false even if it is declared on a supertype. */ public boolean hasOwnProperty(String propertyName) { return hasProperty(propertyName); } /** Returns the names of all

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> the properties directly on this type. */ public Set<String> getOwnPropertyNames() { return new HashSet<String>(); } /** * Checks whether the property's type is inferred. */ public abstract boolean isPropertyTypeInferred(String propertyName); /** * Checks whether the property's type is declared. */ public abstract boolean isPropertyTypeDeclared(String propertyName); /** * Whether the given property is declared on this object. */ boolean hasOwnDeclaredProperty(String name) { return hasOwnProperty(name) && isPropertyTypeDeclared(name); } /** Checks whether the property was defined in the externs. */ public boolean isPropertyInExterns(String propertyName) { return false; } /** * Gets the number of properties of this object. */ public abstract int getPropertiesCount(); /** * Returns a list of properties defined or inferred on this type and any of * its supertypes. */ public Set<String> getPropertyNames() { Set<String> props = Sets.newHashSet(); collectPropertyNames(props); return props; } /** * Adds any properties defined on this type or its supertypes to the set. */ abstract void collectPropertyNames(Set<String> props); @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseObjectType(this); } /** * Checks that the prototype is an implicit prototype of this object. Since * each object has an implicit prototype, an implicit prototype's * implicit prototype is also this implicit prototype's. * * @param prototype any prototype based object * * @return {@code true} if {@code prototype} is {@code equal} to any * object in this object's implicit prototype chain. */ final boolean isImplicitPrototype(ObjectType prototype) { for (ObjectType current = this; current != null; current = current.getImplicitPrototype()) { if (current.isEquivalentTo(prototype)) { return true; } } return false; } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.TRUE; } /** * We treat this as the unknown type if any of its implicit prototype * properties is unknown. */ @Override

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> public boolean isUnknownType() { // If the object is unknown now, check the supertype again, // because it might have been resolved since the last check. if (unknown) { ObjectType implicitProto = getImplicitPrototype(); if (implicitProto == null || implicitProto.isNativeObjectType()) { unknown = false; } else { unknown = implicitProto.isUnknownType(); } } return unknown; } @Override public boolean isObject() { return true; } /** * Returns true if any cached valeus have been set for this type. If true, * then the prototype chain should not be changed, as it might invalidate the * cached values. */ public boolean hasCachedValues() { return !unknown; } /** Whether this is a built-in object. */ public boolean isNativeObjectType() { return false; } /** * A null-safe version of JSType#toObjectType. */ public static ObjectType cast(JSType type) { return type == null ? null : type.toObjectType(); } /** * Gets the interfaces implemented by the ctor associated with this type. * Intended to be overridden by subclasses. */ public Iterable<ObjectType> getCtorImplementedInterfaces() { return ImmutableSet.of(); } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>/* * Copyright 2007 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.javascript.jscomp.CheckLevel; import java.util.logging.Logger; import java.util.logging.Level; /** * An error manager that logs errors and warnings using a logger in addition to * collecting them in memory. Errors are logged at the SEVERE level and warnings * are logged at the WARNING level. * * */ public class LoggerErrorManager extends BasicErrorManager { private final MessageFormatter formatter; private final Logger logger; /** * Creates an instance. */ public LoggerErrorManager(MessageFormatter formatter, Logger logger) { this.formatter = formatter; this.logger = logger; } /** * Creates an instance with a source-less error formatter. */ public LoggerErrorManager(Logger logger) { this(ErrorFormat.SOURCELESS.toFormatter(null, false), logger); } @Override public void println(CheckLevel level, JSError error) { switch (level) { case ERROR: logger.severe(error.format(level, formatter)); break; case WARNING: logger.warning(error.format(level, formatter)); break; } } @Override protected void printSummary() { Level level = (getErrorCount() + getWarningCount() == 0) ? Level.INFO : Level.WARNING; if (getTypedPercent() > 0.0) { logger.log(level, "{0} error(s), {1} warning(s), {2,number,#.#}% typed", new Object[] {getErrorCount

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> /** * Create a named type based on the reference. */ NamedType(JSTypeRegistry registry, String reference, String sourceName, int lineno, int charno) { super(registry, registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE)); Preconditions.checkNotNull(reference); this.reference = reference; this.sourceName = sourceName; this.lineno = lineno; this.charno = charno; } @Override void forgiveUnknownNames() { forgiving = true; } /** Returns the type to which this refers (which is unknown if unresolved). */ public JSType getReferencedType() { return referencedType; } @Override public String getReferenceName() { return reference; } @Override public String toString() { return reference; } @Override public boolean hasReferenceName() { return true; } @Override boolean isNamedType() { return true; } @Override public boolean isNominalType() { return true; } /** * Two named types are equivalent if they are the same {@code * ObjectType} object. This is complicated by the fact that isEquivalent * is sometimes called before we have a chance to resolve the type * names. * * @return {@code true} iff {@code that} == {@code this} or {@code that} * is a {@link NamedType} whose reference is the same as ours, * or {@code that} is the type we reference. */ @Override public boolean isEquivalentTo(JSType that) { if (this == that) { return true; } ObjectType objType = ObjectType.cast(that); if (objType != null) { return objType.isNominalType() && reference.equals(objType.getReferenceName()); } return false; } @Override public int hashCode() { return reference.hashCode(); } /** * Resolve the referenced type within the enclosing scope. */ @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> enclosing) { // TODO(user): Investigate whether it is really necessary to keep two // different mechanisms for resolving named types, and if so, which

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>/* * Copyright 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.javascript.jscomp.SourceExcerptProvider.SourceExcerpt; /** * Error formats available. */ public enum ErrorFormat { LEGACY { @Override public MessageFormatter toFormatter( SourceExcerptProvider source, boolean colorize) { VerboseMessageFormatter formatter = new VerboseMessageFormatter(source); formatter.setColorize(colorize); return formatter; } }, SINGLELINE { @Override public MessageFormatter toFormatter( SourceExcerptProvider source, boolean colorize) { LightweightMessageFormatter formatter = new LightweightMessageFormatter( source); formatter.setColorize(colorize); return formatter; } }, MULTILINE { @Override public MessageFormatter toFormatter( SourceExcerptProvider source, boolean colorize) { LightweightMessageFormatter formatter = new LightweightMessageFormatter( source, SourceExcerpt.REGION); formatter.setColorize(colorize); return formatter; } }, SOURCELESS { @Override public MessageFormatter toFormatter( SourceExcerptProvider source, boolean colorize) { LightweightMessageFormatter formatter = LightweightMessageFormatter.withoutSource(); formatter.setColorize(colorize); return formatter; } }; /** * Convert to a concrete formatter. */ public abstract MessageFormatter toFormatter( SourceExcerptProvider source, boolean colorize); }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> assign {@code x} a type within the {@code f(x)} * call. Since it has no possible type, we assign {@code x} the NoType, * so that {@code f(x)} is legal no matter what the type of {@code f}'s * first argument is. * * * @see <a href="http://en.wikipedia.org/wiki/Bottom_type">Bottom types</a> */ public final class NoType extends NoObjectType { private static final long serialVersionUID = 1L; NoType(JSTypeRegistry registry) { super(registry); } @Override public boolean isNoObjectType() { return false; } @Override public boolean isNoType() { return true; } @Override public boolean isNullable() { return true; } @Override public boolean isSubtype(JSType that) { return true; } @Override public JSType getLeastSupertype(JSType that) { return that; } @Override public JSType getGreatestSubtype(JSType that) { if (that.isUnknownType()) { return registry.getNativeType(JSTypeNative.UNKNOWN_TYPE); } return this; } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.EMPTY; } @Override public boolean matchesNumberContext() { return true; } @Override public boolean matchesObjectContext() { return true; } @Override public boolean matchesStringContext() { return true; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseNoType(); } @Override public String toString() { return "None"; } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>/* * Copyright 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.collect.Sets; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.jstype.FunctionType; import com.google.javascript.rhino.jstype.JSType; import com.google.javascript.rhino.jstype.ObjectType; import java.nio.charset.Charset; import java.util.Set; /** * A code generator that outputs type annotations for functions and * constructors. * */ class TypedCodeGenerator extends CodeGenerator { TypedCodeGenerator(CodeConsumer consumer, Charset outputCharset) { super(consumer, outputCharset); } @Override void add(Node n, Context context) { Node parent = n.getParent(); if (parent != null && (parent.getType() == Token.BLOCK || parent.getType() == Token.SCRIPT)) { if (n.getType() == Token.FUNCTION) { add(getFunctionAnnotation(n)); } else if (n.getType() == Token.EXPR_RESULT && n.getFirstChild().getType() == Token.ASSIGN) { Node rhs = n.getFirstChild().getLastChild(); add(getTypeAnnotation(rhs)); } else if (n.getType() == Token.VAR && n.getFirstChild().getFirstChild() != null && n.getFirstChild().getFirstChild().getType() == Token.FUNCTION) { add(getFunctionAnnotation(n.getFirstChild().getFirstChild

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>Type; ParameterizedType( JSTypeRegistry registry, ObjectType objectType, JSType parameterType) { super(registry, objectType); this.parameterType = parameterType; } @Override public JSType getParameterType() { return parameterType; } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>; ObjectType referencedType; ProxyObjectType(JSTypeRegistry registry, ObjectType referencedType) { super(registry); this.referencedType = referencedType; } @Override public String getReferenceName() { return referencedType.getReferenceName(); } @Override public boolean hasReferenceName() { return referencedType.hasReferenceName(); } @Override public boolean matchesNumberContext() { return referencedType.matchesNumberContext(); } @Override public boolean matchesStringContext() { return referencedType.matchesStringContext(); } @Override public boolean matchesObjectContext() { return referencedType.matchesObjectContext(); } @Override public boolean canBeCalled() { return referencedType.canBeCalled(); } @Override public boolean isUnknownType() { return referencedType.isUnknownType(); } @Override public boolean isCheckedUnknownType() { return referencedType.isCheckedUnknownType(); } @Override public boolean isNullable() { return referencedType.isNullable(); } @Override public boolean isFunctionPrototypeType() { return referencedType.isFunctionPrototypeType(); } @Override public boolean isEnumType() { return referencedType.isEnumType(); } @Override public boolean isEnumElementType() { return referencedType.isEnumElementType(); } @Override public boolean isConstructor() { return referencedType.isConstructor(); } @Override public boolean isNominalType() { return referencedType.isNominalType(); } @Override public boolean isInstanceType() { return referencedType.isInstanceType(); } @Override public boolean isInterface() { return referencedType.isInterface(); } @Override public boolean isOrdinaryFunction() { return referencedType.isOrdinaryFunction(); } @Override public TernaryValue testForEquality(JSType that) { return referencedType.testForEquality(that); } @Override public boolean isSubtype(JSType that) { return referencedType.isSubtype(that); } @Override public Iterable<ObjectType> getCtorImplementedInterfaces() { return referencedType.getCtorImplementedInterfaces(); } @Override public boolean canAssignTo(JSType that) { return referencedType.can

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>AssignTo(that); } @Override public boolean isEquivalentTo(JSType that) { if (this == that) { return true; } return referencedType.isEquivalentTo(that); } @Override public int hashCode() { return referencedType.hashCode(); } @Override public String toString() { return referencedType.toString(); } @Override public ObjectType getImplicitPrototype() { return referencedType.getImplicitPrototype(); } @Override boolean defineProperty(String propertyName, JSType type, boolean inferred, boolean inExterns) { return referencedType.defineProperty(propertyName, type, inferred, inExterns); } @Override public boolean isPropertyTypeDeclared(String propertyName) { return referencedType.isPropertyTypeDeclared(propertyName); } @Override public boolean isPropertyTypeInferred(String propertyName) { return referencedType.isPropertyTypeInferred(propertyName); } @Override public boolean isPropertyInExterns(String propertyName) { return referencedType.isPropertyInExterns(propertyName); } @Override public int getPropertiesCount() { return referencedType.getPropertiesCount(); } @Override protected void collectPropertyNames(Set<String> props) { referencedType.collectPropertyNames(props); } @Override public JSType findPropertyType(String propertyName) { return referencedType.findPropertyType(propertyName); } @Override public JSType getPropertyType(String propertyName) { return referencedType.getPropertyType(propertyName); } @Override public JSDocInfo getJSDocInfo() { return referencedType.getJSDocInfo(); } @Override public void setJSDocInfo(JSDocInfo info) { referencedType.setJSDocInfo(info); } @Override public JSDocInfo getOwnPropertyJSDocInfo(String propertyName) { return referencedType.getOwnPropertyJSDocInfo(propertyName); } @Override public void setPropertyJSDocInfo(String propertyName, JSDocInfo info, boolean inExterns) { referencedType.setPropertyJSDocInfo(propertyName, info, inExterns); } @Override public boolean hasProperty(String propertyName) { return referenced

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>Type.hasProperty(propertyName); } @Override public boolean hasOwnProperty(String propertyName) { return referencedType.hasOwnProperty(propertyName); } @Override public Set<String> getOwnPropertyNames() { return referencedType.getOwnPropertyNames(); } @Override public FunctionType getConstructor() { return referencedType.getConstructor(); } @Override public JSType getParameterType() { return referencedType.getParameterType(); } @Override public JSType getIndexType() { return referencedType.getIndexType(); } @Override public <T> T visit(Visitor<T> visitor) { return referencedType.visit(visitor); } @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) { referencedType = (ObjectType) referencedType.resolve(t, scope); return this; } @Override public String toDebugHashCodeString() { return "{proxy:" + referencedType.toDebugHashCodeString() + "}"; } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> private JSType currentClass = null; CheckAccessControls(AbstractCompiler compiler) { this.compiler = compiler; this.validator = compiler.getTypeValidator(); } public void process(Node externs, Node root) { NodeTraversal.traverse(compiler, root, this); } public void enterScope(NodeTraversal t) { if (!t.inGlobalScope()) { Node n = t.getScopeRoot(); Node parent = n.getParent(); if (isDeprecatedFunction(n, parent)) { deprecatedDepth++; } if (methodDepth == 0) { currentClass = getClassOfMethod(n, parent); } methodDepth++; } } public void exitScope(NodeTraversal t) { if (!t.inGlobalScope()) { Node n = t.getScopeRoot(); Node parent = n.getParent(); if (isDeprecatedFunction(n, parent)) { deprecatedDepth--; } methodDepth--; if (methodDepth == 0) { currentClass = null; } } } /** * Gets the type of the class that "owns" a method, or null if * we know that its un-owned. */ private JSType getClassOfMethod(Node n, Node parent) { if (parent.getType() == Token.ASSIGN) { Node lValue = parent.getFirstChild(); if (lValue.isQualifiedName()) { if (lValue.getType() == Token.GETPROP) { // We have an assignment of the form "a.b = ...". JSType lValueType = lValue.getJSType(); if (lValueType != null && lValueType.isConstructor()) { // If a.b is a constructor, then everything in this function // belongs to the "a.b" type. return ((FunctionType) lValueType).getInstanceType(); } else { // If a.b is not a constructor, then treat this as a method // of whatever type is on "a". return normalizeClassType(lValue.getFirstChild().getJSType()); } } else { // We have an assignment of the form "a = ...", so pull the // type off the "a". return normalizeClassType(lValue.getJSType()); } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> } else if (NodeUtil.isFunctionDeclaration(n) || parent.getType() == Token.NAME) { return normalizeClassType(n.getJSType()); } return null; } /** * Normalize the type of a constructor, its instance, and its prototype * all down to the same type (the instance type). */ private JSType normalizeClassType(JSType type) { if (type == null || type.isUnknownType()) { return type; } else if (type.isConstructor()) { return ((FunctionType) type).getInstanceType(); } else if (type.isFunctionPrototypeType()) { FunctionType owner = ((FunctionPrototypeType) type).getOwnerFunction(); if (owner.isConstructor()) { return owner.getInstanceType(); } } return type; } public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) { return true; } public void visit(NodeTraversal t, Node n, Node parent) { switch (n.getType()) { case Token.NAME: checkNameDeprecation(t, n, parent); checkNameVisibility(t, n, parent); break; case Token.GETPROP: checkPropertyDeprecation(t, n, parent); checkPropertyVisibility(t, n, parent); break; case Token.NEW: checkConstructorDeprecation(t, n, parent); break; } } /** * Checks the given NEW node to ensure that access restrictions are obeyed. */ private void checkConstructorDeprecation(NodeTraversal t, Node n, Node parent) { JSType type = n.getJSType(); if (type != null) { String deprecationInfo = getTypeDeprecationInfo(type); if (deprecationInfo != null && shouldEmitDeprecationWarning(t, n, parent)) { if (!deprecationInfo.isEmpty()) { compiler.report( t.makeError(n, DEPRECATED_CLASS_REASON, type.toString(), deprecationInfo)); } else { compiler.report( t.makeError(n, DEPRECATED_CLASS, type.toString())); } } } } /** * Checks the given NAME node to ensure that access restrictions are obeyed. */ private void checkNameDe

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> = new CrossModuleMethodMotion.IdGenerator(); /** * Keys are arguments passed to getCssName() found during compilation; values * are the number of times the key appeared as an argument to getCssName(). */ private Map<String, Integer> cssNames = null; /** The variable renaming map */ private VariableMap variableMap = null; /** The property renaming map */ private VariableMap propertyMap = null; /** The naming map for anonymous functions */ private VariableMap anonymousFunctionNameMap = null; /** Fully qualified function names and globally unique ids */ private FunctionNames functionNames = null; /** String replacement map */ private VariableMap stringMap = null; public DefaultPassConfig(CompilerOptions options) { super(options); } @Override State getIntermediateState() { return new State( cssNames == null ? null : Maps.newHashMap(cssNames), exportedNames == null ? null : Collections.unmodifiableSet(exportedNames), crossModuleIdGenerator, variableMap, propertyMap, anonymousFunctionNameMap, stringMap, functionNames); } @Override void setIntermediateState(State state) { this.cssNames = state.cssNames == null ? null : Maps.newHashMap(state.cssNames); this.exportedNames = state.exportedNames == null ? null : Sets.newHashSet(state.exportedNames); this.crossModuleIdGenerator = state.crossModuleIdGenerator; this.variableMap = state.variableMap; this.propertyMap = state.propertyMap; this.anonymousFunctionNameMap = state.anonymousFunctionNameMap; this.stringMap = state.stringMap; this.functionNames = state.functionNames; } @Override protected List<PassFactory> getChecks() { List<PassFactory> checks = Lists.newArrayList(); if (options.closurePass) { checks.add(closureGoogScopeAliases); } if (options.nameAnonymousFunctionsOnly) { if (options.anonymousFunctionNaming == AnonymousFunctionNamingPolicy.MAPPED) { checks.add(nameMappedAnonymousFunctions); } else if (options.anonymousFunctionNaming == AnonymousFunctionNamingPolicy.UNMAPPED) { checks.add(nameUnmappedAnonymousFunctions); } return checks;

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>.nameReferenceReportPath.isEmpty()) { checks.add(printNameReferenceReport); } assertAllOneTimePasses(checks); return checks; } @Override protected List<PassFactory> getOptimizations() { List<PassFactory> passes = Lists.newArrayList(); // TODO(nicksantos): The order of these passes makes no sense, and needs // to be re-arranged. if (options.runtimeTypeCheck) { passes.add(runtimeTypeCheck); } passes.add(createEmptyPass("beforeStandardOptimizations")); if (!options.idGenerators.isEmpty()) { passes.add(replaceIdGenerators); } // Optimizes references to the arguments variable. if (options.optimizeArgumentsArray) { passes.add(optimizeArgumentsArray); } // Remove all parameters that are constants or unused. if (options.optimizeParameters) { passes.add(removeUselessParameters); } // Abstract method removal works best on minimally modified code, and also // only needs to run once. if (options.closurePass && options.removeAbstractMethods) { passes.add(removeAbstractMethods); } // Collapsing properties can undo constant inlining, so we do this before // the main optimization loop. if (options.collapseProperties) { passes.add(collapseProperties); } // Tighten types based on actual usage. if (options.tightenTypes) { passes.add(tightenTypesBuilder); } // Property disambiguation should only run once and needs to be done // soon after type checking, both so that it can make use of type // information and so that other passes can take advantage of the renamed // properties. if (options.disambiguateProperties) { passes.add(disambiguateProperties); } if (options.computeFunctionSideEffects) { passes.add(markPureFunctions); } else if (options.markNoSideEffectCalls) { // TODO(user) The properties that this pass adds to CALL and NEW // AST nodes increase the AST's in-memory size. Given that we are // already running close to our memory limits, we could run into // trouble if we end up using the @nosideeffects annotation

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> Write a CompilerPass for this. final PassFactory suspiciousCode = new PassFactory("suspiciousCode", true) { @Override protected CompilerPass createInternal(final AbstractCompiler compiler) { List<Callback> sharedCallbacks = Lists.newArrayList(); if (options.checkSuspiciousCode) { sharedCallbacks.add(new CheckAccidentalSemicolon(CheckLevel.WARNING)); sharedCallbacks.add(new CheckSideEffects(CheckLevel.WARNING)); } CheckLevel checkGlobalThisLevel = options.checkGlobalThisLevel; if (checkGlobalThisLevel.isOn()) { sharedCallbacks.add( new CheckGlobalThis(compiler, checkGlobalThisLevel)); } return combineChecks(compiler, sharedCallbacks); } }; /** Verify that all the passes are one-time passes. */ private void assertAllOneTimePasses(List<PassFactory> passes) { for (PassFactory pass : passes) { Preconditions.checkState(pass.isOneTimePass()); } } /** Verify that all the passes are multi-run passes. */ private void assertAllLoopablePasses(List<PassFactory> passes) { for (PassFactory pass : passes) { Preconditions.checkState(!pass.isOneTimePass()); } } /** Checks for validity of the control structures. */ private final PassFactory checkControlStructures = new PassFactory("checkControlStructures", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new ControlStructureCheck(compiler); } }; /** Checks that all constructed classes are goog.require()d. */ private final PassFactory checkRequires = new PassFactory("checkRequires", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new CheckRequiresForConstructors(compiler, options.checkRequires); } }; /** Makes sure @constructor is paired with goog.provides(). */ private final PassFactory checkProvides = new PassFactory("checkProvides", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new CheckProvides(compiler, options.checkProvides); } }; private static final DiagnosticType GENERATE_EXPORTS_ERROR = DiagnosticType.error( "JSC_GENERATE_EXPORT

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>S_ERROR", "Exports can only be generated if export symbol/property " + "functions are set."); /** Generates exports for @export annotations. */ private final PassFactory generateExports = new PassFactory("generateExports", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { CodingConvention convention = compiler.getCodingConvention(); if (convention.getExportSymbolFunction() != null && convention.getExportPropertyFunction() != null) { return new GenerateExports(compiler, convention.getExportSymbolFunction(), convention.getExportPropertyFunction()); } else { return new ErrorPass(compiler, GENERATE_EXPORTS_ERROR); } } }; /** Generates exports for functions associated with JSUnit. */ private final PassFactory exportTestFunctions = new PassFactory("exportTestFunctions", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { CodingConvention convention = compiler.getCodingConvention(); if (convention.getExportSymbolFunction() != null) { return new ExportTestFunctions(compiler, convention.getExportSymbolFunction()); } else { return new ErrorPass(compiler, GENERATE_EXPORTS_ERROR); } } }; /** Raw exports processing pass. */ final PassFactory gatherRawExports = new PassFactory("gatherRawExports", false) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { final GatherRawExports pass = new GatherRawExports( compiler); return new CompilerPass() { @Override public void process(Node externs, Node root) { pass.process(externs, root); if (exportedNames == null) { exportedNames = Sets.newHashSet(); } exportedNames.addAll(pass.getExportedVariableNames()); } }; } }; /** Closure pre-processing pass. */ @SuppressWarnings("deprecation") final PassFactory closurePrimitives = new PassFactory("processProvidesAndRequires", false) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { final ProcessClosurePrimitives pass = new ProcessClosurePrimitives( compiler, options.brokenClosureRequiresLevel, options.rewriteNewDateGoogNow); return new CompilerPass() { @Override public void process(Node externs, Node

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> root) { pass.process(externs, root); exportedNames = pass.getExportedVariableNames(); } }; } }; /** * The default i18n pass. * A lot of the options are not configurable, because ReplaceMessages * has a lot of legacy logic. */ private final PassFactory replaceMessages = new PassFactory("replaceMessages", true) { @Override protected CompilerPass createInternal(final AbstractCompiler compiler) { return new ReplaceMessages(compiler, options.messageBundle, /* warn about message dupes */ true, /* allow messages with goog.getMsg */ JsMessage.Style.getFromParams(true, false), /* if we can't find a translation, don't worry about it. */ false); } }; /** Applies aliases and inlines goog.scope. */ final PassFactory closureGoogScopeAliases = new PassFactory("processGoogScopeAliases", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new ScopedAliases(compiler); } }; /** Checks that CSS class names are wrapped in goog.getCssName */ private final PassFactory closureCheckGetCssName = new PassFactory("checkMissingGetCssName", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { String blacklist = options.checkMissingGetCssNameBlacklist; Preconditions.checkState(blacklist != null && !blacklist.isEmpty(), "Not checking use of goog.getCssName because of empty blacklist."); return new CheckMissingGetCssName( compiler, options.checkMissingGetCssNameLevel, blacklist); } }; /** * Processes goog.getCssName. The cssRenamingMap is used to lookup * replacement values for the classnames. If null, the raw class names are * inlined. */ private final PassFactory closureReplaceGetCssName = new PassFactory("renameCssNames", true) { @Override protected CompilerPass createInternal(final AbstractCompiler compiler) { return new CompilerPass() { @Override public void process(Node externs, Node jsRoot) { Map<String, Integer> newCssNames = null; if (options.gatherCssNames) { newCssNames = Maps.new

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>HashMap(); } (new ReplaceCssNames(compiler, newCssNames)).process( externs, jsRoot); cssNames = newCssNames; } }; } }; /** * Creates synthetic blocks to prevent FoldConstants from moving code * past markers in the source. */ private final PassFactory createSyntheticBlocks = new PassFactory("createSyntheticBlocks", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new CreateSyntheticBlocks(compiler, options.syntheticBlockStartMarker, options.syntheticBlockEndMarker); } }; /** Various peephole optimizations. */ private final PassFactory peepholeOptimizations = new PassFactory("peepholeOptimizations", false) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new PeepholeOptimizationsPass(compiler, new PeepholeSubstituteAlternateSyntax(), new PeepholeRemoveDeadCode(), new PeepholeFoldConstants()); } }; /** Checks that all variables are defined. */ private final PassFactory checkVars = new PassFactory("checkVars", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new VarCheck(compiler); } }; /** Checks for RegExp references. */ private final PassFactory checkRegExp = new PassFactory("checkRegExp", true) { @Override protected CompilerPass createInternal(final AbstractCompiler compiler) { final CheckRegExp pass = new CheckRegExp(compiler); return new CompilerPass() { @Override public void process(Node externs, Node root) { pass.process(externs, root); compiler.setHasRegExpGlobalReferences( pass.isGlobalRegExpPropertiesUsed()); } }; } }; /** Checks that no vars are illegally shadowed. */ private final PassFactory checkShadowVars = new PassFactory("variableShadowDeclarationCheck", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new VariableShadowDeclarationCheck( compiler, options.checkShadowVars); } }; /** Checks that references to variables look reasonable. */ private final PassFactory checkVariableReferences = new PassFactory("checkVariableReferences", true)

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new VariableReferenceCheck( compiler, options.aggressiveVarCheck); } }; /** Pre-process goog.testing.ObjectPropertyString. */ private final PassFactory objectPropertyStringPreprocess = new PassFactory("ObjectPropertyStringPreprocess", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new ObjectPropertyStringPreprocess(compiler); } }; /** Creates a typed scope and adds types to the type registry. */ final PassFactory resolveTypes = new PassFactory("resolveTypes", false) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new GlobalTypeResolver(compiler); } }; /** Rusn type inference. */ final PassFactory inferTypes = new PassFactory("inferTypes", false) { @Override protected CompilerPass createInternal(final AbstractCompiler compiler) { return new CompilerPass() { @Override public void process(Node externs, Node root) { Preconditions.checkNotNull(topScope); Preconditions.checkNotNull(typedScopeCreator); makeTypeInference(compiler).process(externs, root); } }; } }; /** Checks type usage */ private final PassFactory checkTypes = new PassFactory("checkTypes", false) { @Override protected CompilerPass createInternal(final AbstractCompiler compiler) { return new CompilerPass() { @Override public void process(Node externs, Node root) { Preconditions.checkNotNull(topScope); Preconditions.checkNotNull(typedScopeCreator); TypeCheck check = makeTypeCheck(compiler); check.process(externs, root); compiler.getErrorManager().setTypedPercent(check.getTypedPercent()); } }; } }; /** * Checks possible execution paths of the program for problems: missing return * statements and dead code. */ private final PassFactory checkControlFlow = new PassFactory("checkControlFlow", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { List<Callback> callbacks = Lists.newArrayList(); if (options.checkUnreachableCode.isOn()) { callbacks.add( new CheckUnreachableCode(compiler, options.checkUnreachableCode)); } if (options

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>.checkMissingReturn.isOn() && options.checkTypes) { callbacks.add( new CheckMissingReturn(compiler, options.checkMissingReturn)); } return combineChecks(compiler, callbacks); } }; /** Checks access controls. Depends on type-inference. */ private final PassFactory checkAccessControls = new PassFactory("checkAccessControls", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new CheckAccessControls(compiler); } }; /** Executes the given callbacks with a {@link CombinedCompilerPass}. */ private static CompilerPass combineChecks(AbstractCompiler compiler, List<Callback> callbacks) { Preconditions.checkArgument(callbacks.size() > 0); Callback[] array = callbacks.toArray(new Callback[callbacks.size()]); return new CombinedCompilerPass(compiler, array); } /** A compiler pass that resolves types in the global scope. */ private class GlobalTypeResolver implements CompilerPass { private final AbstractCompiler compiler; GlobalTypeResolver(AbstractCompiler compiler) { this.compiler = compiler; } @Override public void process(Node externs, Node root) { if (topScope == null) { typedScopeCreator = new MemoizedScopeCreator(new TypedScopeCreator(compiler)); topScope = typedScopeCreator.createScope(root.getParent(), null); } else { compiler.getTypeRegistry().resolveTypesInScope(topScope); } } } /** Checks global name usage. */ private final PassFactory checkGlobalNames = new PassFactory("Check names", true) { @Override protected CompilerPass createInternal(final AbstractCompiler compiler) { return new CompilerPass() { @Override public void process(Node externs, Node jsRoot) { // Create a global namespace for analysis by check passes. // Note that this class does all heavy computation lazily, // so it's OK to create it here. namespaceForChecks = new GlobalNamespace(compiler, jsRoot); new CheckGlobalNames(compiler, options.checkGlobalNamesLevel) .injectNamespace(namespaceForChecks).process(externs, jsRoot); } }; } }; /** Checks for properties that are not read or written */ private final PassFactory checkSuspiciousProperties

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> = new PassFactory("checkSuspiciousProperties", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new SuspiciousPropertiesCheck( compiler, options.checkUndefinedProperties, options.checkUnusedPropertiesEarly ? CheckLevel.WARNING : CheckLevel.OFF); } }; /** Checks that the code is ES5 or Caja compliant. */ private final PassFactory checkStrictMode = new PassFactory("checkStrictMode", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new StrictModeCheck(compiler, !options.checkSymbols, // don't check variables twice !options.checkCaja); // disable eval check if not Caja } }; /** Override @define-annotated constants. */ final PassFactory processDefines = new PassFactory("processDefines", true) { @Override protected CompilerPass createInternal(final AbstractCompiler compiler) { return new CompilerPass() { @Override public void process(Node externs, Node jsRoot) { Map<String, Node> replacements = getAdditionalReplacements(options); replacements.putAll(options.getDefineReplacements()); new ProcessDefines(compiler, replacements) .injectNamespace(namespaceForChecks).process(externs, jsRoot); // Kill the namespace in the other class // so that it can be garbage collected after all passes // are through with it. namespaceForChecks = null; } }; } }; /** Checks that all constants are not modified */ private final PassFactory checkConsts = new PassFactory("checkConsts", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new ConstCheck(compiler); } }; /** Computes the names of functions for later analysis. */ private final PassFactory computeFunctionNames = new PassFactory("computeFunctionNames", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return ((functionNames = new FunctionNames(compiler))); } }; /** Skips Caja-private properties in for-in loops */ private final PassFactory ignoreCajaProperties = new PassFactory("ignoreCajaProperties", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler)

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> { return new IgnoreCajaProperties(compiler); } }; /** Inserts runtime type assertions for debugging. */ private final PassFactory runtimeTypeCheck = new PassFactory("runtimeTypeCheck", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new RuntimeTypeCheck(compiler, options.runtimeTypeCheckLogFunction); } }; /** Generates unique ids. */ private final PassFactory replaceIdGenerators = new PassFactory("replaceIdGenerators", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new ReplaceIdGenerators(compiler, options.idGenerators); } }; /** Replace strings. */ private final PassFactory replaceStrings = new PassFactory("replaceStrings", true) { @Override protected CompilerPass createInternal(final AbstractCompiler compiler) { VariableMap map = null; return new CompilerPass() { @Override public void process(Node externs, Node root) { ReplaceStrings pass = new ReplaceStrings( compiler, options.replaceStringsPlaceholderToken, options.replaceStringsFunctionDescriptions); pass.process(externs, root); stringMap = pass.getStringMap(); } }; } }; /** Optimizes the "arguments" array. */ private final PassFactory optimizeArgumentsArray = new PassFactory("optimizeArgumentsArray", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new OptimizeArgumentsArray(compiler); } }; /** Removes unused or constant formal parameters. */ private final PassFactory removeUselessParameters = new PassFactory("optimizeParameters", true) { @Override protected CompilerPass createInternal(final AbstractCompiler compiler) { return new CompilerPass() { @Override public void process(Node externs, Node root) { NameReferenceGraphConstruction c = new NameReferenceGraphConstruction(compiler); c.process(externs, root); (new OptimizeParameters(compiler, c.getNameReferenceGraph())).process( externs, root); } }; } }; /** Remove variables set to goog.abstractMethod. */ private final PassFactory removeAbstractMethods = new PassFactory("removeAbstractMethods", true) { @Override protected CompilerPass createInternal(final AbstractCompiler compiler) { return new Google

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>CodeRemoval(compiler); } }; /** Collapses names in the global scope. */ private final PassFactory collapseProperties = new PassFactory("collapseProperties", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new CollapseProperties( compiler, options.collapsePropertiesOnExternTypes, !isInliningForbidden()); } }; /** * Try to infer the actual types, which may be narrower * than the declared types. */ private final PassFactory tightenTypesBuilder = new PassFactory("tightenTypes", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { if (!options.checkTypes) { return new ErrorPass(compiler, TIGHTEN_TYPES_WITHOUT_TYPE_CHECK); } tightenTypes = new TightenTypes(compiler); return tightenTypes; } }; /** Devirtualize property names based on type information. */ private final PassFactory disambiguateProperties = new PassFactory("disambiguateProperties", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { if (tightenTypes == null) { return DisambiguateProperties.forJSTypeSystem(compiler); } else { return DisambiguateProperties.forConcreteTypeSystem( compiler, tightenTypes); } } }; /** * Chain calls to functions that return this. */ private final PassFactory chainCalls = new PassFactory("chainCalls", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new ChainCalls(compiler); } }; /** * Rewrite instance methods as static methods, to make them easier * to inline. */ private final PassFactory devirtualizePrototypeMethods = new PassFactory("devirtualizePrototypeMethods", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new DevirtualizePrototypeMethods(compiler); } }; /** * Look for function calls that are pure, and annotate them * that way. */ private final PassFactory markPureFunctions = new PassFactory("markPureFunctions", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new PureFunctionMarker

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>( compiler, options.debugFunctionSideEffectsPath, false); } }; /** * Look for function calls that have no side effects, and annotate them * that way. */ private final PassFactory markNoSideEffectCalls = new PassFactory("markNoSideEffectCalls", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new MarkNoSideEffectCalls(compiler); } }; /** Inlines variables heuristically. */ private final PassFactory inlineVariables = new PassFactory("inlineVariables", false) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { if (isInliningForbidden()) { // In old renaming schemes, inlining a variable can change whether // or not a property is renamed. This is bad, and those old renaming // schemes need to die. return new ErrorPass(compiler, CANNOT_USE_PROTOTYPE_AND_VAR); } else { InlineVariables.Mode mode; if (options.inlineVariables) { mode = InlineVariables.Mode.ALL; } else if (options.inlineLocalVariables) { mode = InlineVariables.Mode.LOCALS_ONLY; } else { throw new IllegalStateException("No variable inlining option set."); } return new InlineVariables(compiler, mode, true); } } }; /** Inlines variables that are marked as constants. */ private final PassFactory inlineConstants = new PassFactory("inlineConstants", false) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new InlineVariables( compiler, InlineVariables.Mode.CONSTANTS_ONLY, true); } }; /** * Simplify expressions by removing the parts that have no side effects. */ private final PassFactory removeConstantExpressions = new PassFactory("removeConstantExpressions", false) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new RemoveConstantExpressions(compiler); } }; /** * Perform local control flow optimizations. */ private final PassFactory minimizeExitPoints = new PassFactory("minimizeExitPoints", false) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new MinimizeExitPoints(compiler); } }; /** * Use data flow analysis to

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> remove dead branches. */ private final PassFactory removeUnreachableCode = new PassFactory("removeUnreachableCode", false) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new UnreachableCodeElimination(compiler, true); } }; /** * Remove prototype properties that do not appear to be used. */ private final PassFactory removeUnusedPrototypeProperties = new PassFactory("removeUnusedPrototypeProperties", false) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new RemoveUnusedPrototypeProperties( compiler, options.removeUnusedPrototypePropertiesInExterns, !options.removeUnusedVars); } }; /** * Process smart name processing - removes unused classes and does referencing * starting with minimum set of names. */ private final PassFactory smartNamePass = new PassFactory("smartNamePass", true) { @Override protected CompilerPass createInternal(final AbstractCompiler compiler) { return new CompilerPass() { @Override public void process(Node externs, Node root) { NameAnalyzer na = new NameAnalyzer(compiler, false); na.process(externs, root); String reportPath = options.reportPath; if (reportPath != null) { try { Files.write(na.getHtmlReport(), new File(reportPath), Charsets.UTF_8); } catch (IOException e) { compiler.report(JSError.make(REPORT_PATH_IO_ERROR, reportPath)); } } if (options.smartNameRemoval) { na.removeUnreferenced(); } } }; } }; /** Inlines simple methods, like getters */ private PassFactory inlineGetters = new PassFactory("inlineGetters", false) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new InlineGetters(compiler); } }; /** Kills dead assignments. */ private PassFactory deadAssignmentsElimination = new PassFactory("deadAssignmentsElimination", false) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new DeadAssignmentsElimination(compiler); } }; /** Inlines function calls. */ private PassFactory inlineFunctions = new PassFactory("inlineFunctions", false) {

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> @Override protected CompilerPass createInternal(AbstractCompiler compiler) { boolean enableBlockInlining = !isInliningForbidden(); return new InlineFunctions( compiler, compiler.getUniqueNameIdSupplier(), options.inlineFunctions, options.inlineLocalFunctions, enableBlockInlining); } }; /** Removes variables that are never used. */ private PassFactory removeUnusedVars = new PassFactory("removeUnusedVars", false) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { boolean preserveAnonymousFunctionNames = options.anonymousFunctionNaming != AnonymousFunctionNamingPolicy.OFF; return new RemoveUnusedVars( compiler, options.removeUnusedVarsInGlobalScope, preserveAnonymousFunctionNames); } }; /** * Move global symbols to a deeper common module */ private PassFactory crossModuleCodeMotion = new PassFactory("crossModuleCodeMotion", false) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new CrossModuleCodeMotion(compiler, compiler.getModuleGraph()); } }; /** * Move methods to a deeper common module */ private PassFactory crossModuleMethodMotion = new PassFactory("crossModuleMethodMotion", false) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new CrossModuleMethodMotion( compiler, crossModuleIdGenerator, // Only move properties in externs if we're not treating // them as exports. options.removeUnusedPrototypePropertiesInExterns); } }; /** A data-flow based variable inliner. */ private final PassFactory flowSensitiveInlineVariables = new PassFactory("flowSensitiveInlineVariables", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new FlowSensitiveInlineVariables(compiler); } }; /** Uses register-allocation algorithms to use fewer variables. */ private final PassFactory coalesceVariableNames = new PassFactory("coalesceVariableNames", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new CoalesceVariableNames(compiler, options.generatePseudoNames); } }; /** * Some simple, local collapses (e.g., {@code var x; var y;} becomes * {@code var x,y;}. */ private

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> final PassFactory collapseVariableDeclarations = new PassFactory("collapseVariableDeclarations", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new CollapseVariableDeclarations(compiler); } }; /** * Simple global collapses of variable declarations. */ private final PassFactory groupVariableDeclarations = new PassFactory("groupVariableDeclarations", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new GroupVariableDeclarations(compiler); } }; /** * Extracts common sub-expressions. */ private final PassFactory extractPrototypeMemberDeclarations = new PassFactory("extractPrototypeMemberDeclarations", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new ExtractPrototypeMemberDeclarations(compiler); } }; /** Rewrites common function definitions to be more compact. */ private final PassFactory rewriteFunctionExpressions = new PassFactory("rewriteFunctionExpressions", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new FunctionRewriter(compiler); } }; /** Collapses functions to not use the VAR keyword. */ private final PassFactory collapseAnonymousFunctions = new PassFactory("collapseAnonymousFunctions", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new CollapseAnonymousFunctions(compiler); } }; /** Moves function declarations to the top, to simulate actual hoisting. */ private final PassFactory moveFunctionDeclarations = new PassFactory("moveFunctionDeclarations", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new MoveFunctionDeclarations(compiler); } }; private final PassFactory nameUnmappedAnonymousFunctions = new PassFactory("nameAnonymousFunctions", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new NameAnonymousFunctions(compiler); } }; private final PassFactory nameMappedAnonymousFunctions = new PassFactory("nameAnonymousFunctions", true) { @Override protected CompilerPass createInternal(final AbstractCompiler compiler) { return new CompilerPass() { @Override public void process(Node externs, Node root) { NameAnonymousFunctionsMapped naf = new NameAnonymousFunctionsMapped(compiler); naf.process(externs, root);

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> anonymousFunctionNameMap = naf.getFunctionMap(); } }; } }; /** Alias external symbols. */ private final PassFactory aliasExternals = new PassFactory("aliasExternals", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new AliasExternals(compiler, compiler.getModuleGraph(), options.unaliasableGlobals, options.aliasableGlobals); } }; /** * Alias string literals with global variables, to avoid creating lots of * transient objects. */ private final PassFactory aliasStrings = new PassFactory("aliasStrings", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new AliasStrings( compiler, compiler.getModuleGraph(), options.aliasAllStrings ? null : options.aliasableStrings, options.aliasStringsBlacklist, options.outputJsStringUsage); } }; /** Aliases common keywords (true, false) */ private final PassFactory aliasKeywords = new PassFactory("aliasKeywords", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new AliasKeywords(compiler); } }; /** Handling for the ObjectPropertyString primitive. */ private final PassFactory objectPropertyStringPostprocess = new PassFactory("ObjectPropertyStringPostprocess", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new ObjectPropertyStringPostprocess(compiler); } }; /** * Renames properties so that the two properties that never appear on * the same object get the same name. */ private final PassFactory ambiguateProperties = new PassFactory("ambiguateProperties", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new AmbiguateProperties( compiler, options.anonymousFunctionNaming.getReservedCharacters()); } }; /** * Mark the point at which the normalized AST assumptions no longer hold. */ private final PassFactory markUnnormalized = new PassFactory("markUnnormalized", true) { @Override protected CompilerPass createInternal(final AbstractCompiler compiler) { return new CompilerPass() { @Override public void process(Node externs, Node root) { compiler.setUnnormalized(); } }; } };

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> /** Denormalize the AST for code generation. */ private final PassFactory denormalize = new PassFactory("denormalize", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new Denormalize(compiler); } }; /** Inverting name normalization. */ private final PassFactory invertContextualRenaming = new PassFactory("invertNames", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return MakeDeclaredNamesUnique.getContextualRenameInverter(compiler); } }; /** * Renames properties. */ private final PassFactory renameProperties = new PassFactory("renameProperties", true) { @Override protected CompilerPass createInternal(final AbstractCompiler compiler) { VariableMap map = null; if (options.inputPropertyMapSerialized != null) { try { map = VariableMap.fromBytes(options.inputPropertyMapSerialized); } catch (ParseException e) { return new ErrorPass(compiler, JSError.make(INPUT_MAP_PROP_PARSE, e.getMessage())); } } final VariableMap prevPropertyMap = map; return new CompilerPass() { @Override public void process(Node externs, Node root) { propertyMap = runPropertyRenaming( compiler, prevPropertyMap, externs, root); } }; } }; private VariableMap runPropertyRenaming( AbstractCompiler compiler, VariableMap prevPropertyMap, Node externs, Node root) { char[] reservedChars = options.anonymousFunctionNaming.getReservedCharacters(); switch (options.propertyRenaming) { case HEURISTIC: RenamePrototypes rproto = new RenamePrototypes(compiler, false, reservedChars, prevPropertyMap); rproto.process(externs, root); return rproto.getPropertyMap(); case AGGRESSIVE_HEURISTIC: RenamePrototypes rproto2 = new RenamePrototypes(compiler, true, reservedChars, prevPropertyMap); rproto2.process(externs, root); return rproto2.getPropertyMap(); case ALL_UNQUOTED: RenameProperties rprop = new RenameProperties( compiler, options.generatePseudoNames, prevPropertyMap, reservedChars); rprop.process

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>(externs, root); return rprop.getPropertyMap(); default: throw new IllegalStateException( "Unrecognized property renaming policy"); } } /** Renames variables. */ private final PassFactory renameVars = new PassFactory("renameVars", true) { @Override protected CompilerPass createInternal(final AbstractCompiler compiler) { VariableMap map = null; if (options.inputVariableMapSerialized != null) { try { map = VariableMap.fromBytes(options.inputVariableMapSerialized); } catch (ParseException e) { return new ErrorPass(compiler, JSError.make(INPUT_MAP_VAR_PARSE, e.getMessage())); } } final VariableMap prevVariableMap = map; return new CompilerPass() { @Override public void process(Node externs, Node root) { variableMap = runVariableRenaming( compiler, prevVariableMap, externs, root); } }; } }; private VariableMap runVariableRenaming( AbstractCompiler compiler, VariableMap prevVariableMap, Node externs, Node root) { char[] reservedChars = options.anonymousFunctionNaming.getReservedCharacters(); boolean preserveAnonymousFunctionNames = options.anonymousFunctionNaming != AnonymousFunctionNamingPolicy.OFF; RenameVars rn = new RenameVars( compiler, options.renamePrefix, options.variableRenaming == VariableRenamingPolicy.LOCAL, preserveAnonymousFunctionNames, options.generatePseudoNames, prevVariableMap, reservedChars, exportedNames); rn.process(externs, root); return rn.getVariableMap(); } /** Renames labels */ private final PassFactory renameLabels = new PassFactory("renameLabels", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new RenameLabels(compiler); } }; /** Convert bracket access to dot access */ private final PassFactory convertToDottedProperties = new PassFactory("convertToDottedProperties", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new ConvertToDottedProperties(compiler); } }; /** Checks that all variables are defined. */ private final PassFactory sanityCheckVars = new PassFactory("sanityCheckVars", true) { @Override

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> protected CompilerPass createInternal(AbstractCompiler compiler) { return new VarCheck(compiler, true); } }; /** Adds instrumentations according to an instrumentation template. */ private final PassFactory instrumentFunctions = new PassFactory("instrumentFunctions", true) { @Override protected CompilerPass createInternal(final AbstractCompiler compiler) { return new CompilerPass() { @Override public void process(Node externs, Node root) { try { FileReader templateFile = new FileReader(options.instrumentationTemplate); (new InstrumentFunctions( compiler, functionNames, options.instrumentationTemplate, options.appNameStr, templateFile)).process(externs, root); } catch (IOException e) { compiler.report( JSError.make(AbstractCompiler.READ_ERROR, options.instrumentationTemplate)); } } }; } }; /** * Create a no-op pass that can only run once. Used to break up loops. */ private static PassFactory createEmptyPass(String name) { return new PassFactory(name, true) { @Override protected CompilerPass createInternal(final AbstractCompiler compiler) { return runInSerial(); } }; } /** * Runs custom passes that are designated to run at a particular time. */ private PassFactory getCustomPasses( final CustomPassExecutionTime executionTime) { return new PassFactory("runCustomPasses", true) { @Override protected CompilerPass createInternal(final AbstractCompiler compiler) { return runInSerial(options.customPasses.get(executionTime)); } }; } /** * All inlining is forbidden in heuristic renaming mode, because inlining * will ruin the invariants that it depends on. */ private boolean isInliningForbidden() { return options.propertyRenaming == PropertyRenamingPolicy.HEURISTIC || options.propertyRenaming == PropertyRenamingPolicy.AGGRESSIVE_HEURISTIC; } /** Create a compiler pass that runs the given passes in serial. */ private static CompilerPass runInSerial(final CompilerPass ... passes) { return runInSerial(Lists.newArrayList(passes)); } /** Create a compiler pass that runs the given passes in serial. */ private static CompilerPass runInSerial( final

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> Collection<CompilerPass> passes) { return new CompilerPass() { @Override public void process(Node externs, Node root) { for (CompilerPass pass : passes) { pass.process(externs, root); } } }; } @VisibleForTesting static Map<String, Node> getAdditionalReplacements( CompilerOptions options) { Map<String, Node> additionalReplacements = Maps.newHashMap(); if (options.markAsCompiled || options.closurePass) { additionalReplacements.put(COMPILED_CONSTANT_NAME, new Node(Token.TRUE)); } if (options.closurePass && options.locale != null) { additionalReplacements.put(CLOSURE_LOCALE_CONSTANT_NAME, Node.newString(options.locale)); } return additionalReplacements; } /** A compiler pass that marks pure functions. */ private static class PureFunctionMarker implements CompilerPass { private final AbstractCompiler compiler; private final String reportPath; private final boolean useNameReferenceGraph; PureFunctionMarker(AbstractCompiler compiler, String reportPath, boolean useNameReferenceGraph) { this.compiler = compiler; this.reportPath = reportPath; this.useNameReferenceGraph = useNameReferenceGraph; } @Override public void process(Node externs, Node root) { DefinitionProvider definitionProvider = null; if (useNameReferenceGraph) { NameReferenceGraphConstruction graphBuilder = new NameReferenceGraphConstruction(compiler); graphBuilder.process(externs, root); definitionProvider = graphBuilder.getNameReferenceGraph(); } else { SimpleDefinitionFinder defFinder = new SimpleDefinitionFinder(compiler); defFinder.process(externs, root); definitionProvider = defFinder; } PureFunctionIdentifier pureFunctionIdentifier = new PureFunctionIdentifier(compiler, definitionProvider); pureFunctionIdentifier.process(externs, root); if (reportPath != null) { try { Files.write(pureFunctionIdentifier.getDebugReport(), new File(reportPath), Charsets.UTF_8); } catch (IOException e) { throw new RuntimeException(e); } } } } private final PassFactory printNameReferenceGraph = new PassFactory("printNameReferenceGraph",

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> true) { @Override protected CompilerPass createInternal(final AbstractCompiler compiler) { return new CompilerPass() { @Override public void process(Node externs, Node jsRoot) { NameReferenceGraphConstruction gc = new NameReferenceGraphConstruction(compiler); gc.process(externs, jsRoot); String graphFileName = options.nameReferenceGraphPath; try { Files.write(DotFormatter.toDot(gc.getNameReferenceGraph()), new File(graphFileName), Charsets.UTF_8); } catch (IOException e) { compiler.report( JSError.make( NAME_REF_GRAPH_FILE_ERROR, e.getMessage(), graphFileName)); } } }; } }; private final PassFactory printNameReferenceReport = new PassFactory("printNameReferenceReport", true) { @Override protected CompilerPass createInternal(final AbstractCompiler compiler) { return new CompilerPass() { @Override public void process(Node externs, Node jsRoot) { NameReferenceGraphConstruction gc = new NameReferenceGraphConstruction(compiler); String reportFileName = options.nameReferenceReportPath; try { NameReferenceGraphReport report = new NameReferenceGraphReport(gc.getNameReferenceGraph()); Files.write(report.getHtmlReport(), new File(reportFileName), Charsets.UTF_8); } catch (IOException e) { compiler.report( JSError.make( NAME_REF_REPORT_FILE_ERROR, e.getMessage(), reportFileName)); } } }; } }; }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> maybeLineBreak() { maybeCutLine(); } void maybeCutLine() { } void endLine() { } void notePreferredLineBreak() { } void beginBlock() { if (statementNeedsEnded) { append(";"); maybeLineBreak(); } appendBlockStart(); endLine(); statementNeedsEnded = false; } void endBlock() { endBlock(false); } void endBlock(boolean shouldEndLine) { appendBlockEnd(); if (shouldEndLine) { endLine(); } statementNeedsEnded = false; } void listSeparator() { add(","); maybeLineBreak(); } /** * Indicates the end of a statement and a ';' may need to be added. * But we don't add it now, in case we're at the end of a block (in which * case we don't have to add the ';'). * See maybeEndStatement() */ void endStatement() { endStatement(false); } void endStatement(boolean needSemiColon) { if (needSemiColon) { append(";"); maybeLineBreak(); statementNeedsEnded = false; } else if (statementStarted) { statementNeedsEnded = true; } } /** * This is to be called when we're in a statement. If the prev statement * needs to be ended, add a ';'. */ void maybeEndStatement() { // Add a ';' if we need to. if (statementNeedsEnded) { append(";"); maybeLineBreak(); endLine(); statementNeedsEnded = false; } statementStarted = true; } void endFunction() { endFunction(false); } void endFunction(boolean statementContext) { sawFunction = true; if (statementContext) { endLine(); } } void beginCaseBody() { append(":"); } void endCaseBody() { } void add(String newcode) { maybeEndStatement(); if (newcode.length() == 0) { return; } char c = newcode.charAt(0); if ((isWordChar(c) || c == '\\') && isWordChar(getLastChar())) { //

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>; import java.util.List; import java.util.SortedSet; import java.util.TreeSet; /** * The {@code UnionType} implements a common JavaScript idiom in which the * code is specifically designed to work with multiple input types. Because * JavaScript always knows the runtime type of an object value, this is safer * than a C union.<p> * * For instance, values of the union type {@code (String,boolean)} can be of * type {@code String} or of type {@code boolean}. The commutativity of the * statement is captured by making {@code (String,boolean)} and * {@code (boolean,String)} equal.<p> * * The implementation of this class prevents the creation of nested * unions.<p> */ public class UnionType extends JSType { private static final long serialVersionUID = 1L; Collection<JSType> alternates; private final int hashcode; /** * Creates a union type. * * @param alternates the alternates of the union */ UnionType(JSTypeRegistry registry, Collection<JSType> alternates) { super(registry); this.alternates = alternates; this.hashcode = this.alternates.hashCode(); } /** * Gets the alternate types of this union type. * @return The alternate types of this union type. The returned set is * immutable. */ public Iterable<JSType> getAlternates() { return alternates; } @Override void forgiveUnknownNames() { for (JSType type : getAlternates()) { type.forgiveUnknownNames(); } } /** * This predicate is used to test whether a given type can appear in a * numeric context, such as an operand of a multiply operator. * * @return true if the type can appear in a numeric context. */ @Override public boolean matchesNumberContext() { // TODO(user): Reverse this logic to make it correct instead of generous. for (JSType t : alternates) { if (t.matchesNumberContext()) { return true; } } return false; } /** * This predicate is used to test whether a given type can appear

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> in a * {@code String} context, such as an operand of a string concat ({@code +}) * operator.<p> * * All types have at least the potential for converting to {@code String}. * When we add externally defined types, such as a browser OM, we may choose * to add types that do not automatically convert to {@code String}. * * @return {@code true} if not {@link VoidType} */ @Override public boolean matchesStringContext() { // TODO(user): Reverse this logic to make it correct instead of generous. for (JSType t : alternates) { if (t.matchesStringContext()) { return true; } } return false; } /** * This predicate is used to test whether a given type can appear in an * {@code Object} context, such as the expression in a {@code with} * statement.<p> * * Most types we will encounter, except notably {@code null}, have at least * the potential for converting to {@code Object}. Host defined objects can * get peculiar.<p> * * VOID type is included here because while it is not part of the JavaScript * language, functions returning 'void' type can't be used as operands of * any operator or statement.<p> * * @return {@code true} if the type is not {@link NullType} or * {@link VoidType} */ @Override public boolean matchesObjectContext() { // TODO(user): Reverse this logic to make it correct instead of generous. for (JSType t : alternates) { if (t.matchesObjectContext()) { return true; } } return false; } @Override public JSType findPropertyType(String propertyName) { JSType propertyType = null; for (JSType alternate : getAlternates()) { // Filter out the null/undefined type. if (alternate.isNullType() || alternate.isVoidType()) { continue; } JSType altPropertyType = alternate.findPropertyType(propertyName); if (altPropertyType == null) { continue; } if (propertyType == null) { propertyType = altPropertyType; } else { propertyType = property

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>Type.getLeastSupertype(altPropertyType); } } return propertyType; } @Override public boolean canAssignTo(JSType that) { boolean canAssign = true; for (JSType t : alternates) { if (t.isUnknownType()) { return true; } canAssign &= t.canAssignTo(that); } return canAssign; } @Override public boolean canBeCalled() { for (JSType t : alternates) { if (!t.canBeCalled()) { return false; } } return true; } @Override public JSType restrictByNotNullOrUndefined() { UnionTypeBuilder restricted = new UnionTypeBuilder(registry); for (JSType t : alternates) { restricted.addAlternate(t.restrictByNotNullOrUndefined()); } return restricted.build(); } @Override public TernaryValue testForEquality(JSType that) { TernaryValue result = null; for (JSType t : alternates) { TernaryValue test = t.testForEquality(that); if (result == null) { result = test; } else if (!result.equals(test)) { return UNKNOWN; } } return result; } /** * This predicate determines whether objects of this type can have the * {@code null} value, and therefore can appear in contexts where * {@code null} is expected. * * @return {@code true} for everything but {@code Number} and * {@code Boolean} types. */ @Override public boolean isNullable() { for (JSType t : alternates) { if (t.isNullable()) { return true; } } return false; } @Override public boolean isUnknownType() { for (JSType t : alternates) { if (t.isUnknownType()) { return true; } } return false; } @Override public JSType getLeastSupertype(JSType that) { if (!that.isUnknownType()) { for (JSType alternate : alternates) { if (!alternate.isUnknownType() && that.isSubtype(alternate)) { return this; }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> } } return getLeastSupertype(this, that); } JSType meet(JSType that) { UnionTypeBuilder builder = new UnionTypeBuilder(registry); for (JSType alternate : alternates) { if (alternate.isSubtype(that)) { builder.addAlternate(alternate); } } if (that instanceof UnionType) { for (JSType otherAlternate : ((UnionType) that).alternates) { if (otherAlternate.isSubtype(this)) { builder.addAlternate(otherAlternate); } } } else if (that.isSubtype(this)) { builder.addAlternate(that); } JSType result = builder.build(); if (!result.isNoType()) { return result; } else if (this.isObject() && that.isObject()) { return getNativeType(JSTypeNative.NO_OBJECT_TYPE); } else { return getNativeType(JSTypeNative.NO_TYPE); } } /** * Two union types are equal if they have the same number of alternates * and all alternates are equal. */ @Override public boolean isEquivalentTo(JSType object) { if (object instanceof UnionType) { UnionType that = (UnionType) object; if (alternates.size() != that.alternates.size()) { return false; } for (JSType alternate : that.alternates) { if (!hasAlternate(alternate)) { return false; } } return true; } else { return false; } } private boolean hasAlternate(JSType type) { for (JSType alternate : alternates) { if (alternate.isEquivalentTo(type)) { return true; } } return false; } @Override public int hashCode() { return this.hashcode; } @Override public boolean isUnionType() { return true; } @Override public boolean isObject() { for (JSType alternate : alternates) { if (!alternate.isObject()) { return false; } } return true; } /** * A {@link UnionType} contains a given type (alternate) iff the member * vector contains it.

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> Since the {@link #equals} method above conforms to * the necessary semantics for the collection, everything works out just * fine. * * @param alternate The alternate which might be in this union. * * @return {@code true} if the alternate is in the union */ public boolean contains(JSType alternate) { return alternates.contains(alternate); } /** * Returns a more restricted union type than {@code this} one, in which all * subtypes of {@code type} have been removed.<p> * * Examples: * <ul> * <li>{@code (number,string)} restricted by {@code number} is * {@code string}</li> * <li>{@code (null, EvalError, URIError)} restricted by * {@code Error} is {@code null}</li> * </ul> * * @param type the supertype of the types to remove from this union type */ public JSType getRestrictedUnion(JSType type) { UnionTypeBuilder restricted = new UnionTypeBuilder(registry); for (JSType t : alternates) { if (t.isUnknownType() || !t.isSubtype(type)) { restricted.addAlternate(t); } } return restricted.build(); } @Override public String toString() { StringBuilder result = new StringBuilder(); boolean firstAlternate = true; result.append("("); SortedSet<JSType> sorted = new TreeSet<JSType>(ALPHA); sorted.addAll(alternates); for (JSType t : sorted) { if (!firstAlternate) { result.append("|"); } result.append(t.toString()); firstAlternate = false; } result.append(")"); return result.toString(); } @Override public boolean isSubtype(JSType that) { for (JSType element : alternates) { if (!element.isSubtype(that)) { return false; } } return true; } @Override public JSType getRestrictedTypeGivenToBooleanOutcome(boolean outcome) { // gather elements after restriction UnionTypeBuilder restricted = new UnionTypeBuilder(registry); for (JSType element : alternates) { restricted.addAlternate(

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> element.getRestrictedTypeGivenToBooleanOutcome(outcome)); } return restricted.build(); } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { BooleanLiteralSet literals = BooleanLiteralSet.EMPTY; for (JSType element : alternates) { literals = literals.union(element.getPossibleToBooleanOutcomes()); if (literals == BooleanLiteralSet.BOTH) { break; } } return literals; } @Override public TypePair getTypesUnderEquality(JSType that) { UnionTypeBuilder thisRestricted = new UnionTypeBuilder(registry); UnionTypeBuilder thatRestricted = new UnionTypeBuilder(registry); for (JSType element : alternates) { TypePair p = element.getTypesUnderEquality(that); if (p.typeA != null) { thisRestricted.addAlternate(p.typeA); } if (p.typeB != null) { thatRestricted.addAlternate(p.typeB); } } return new TypePair( thisRestricted.build(), thatRestricted.build()); } @Override public TypePair getTypesUnderInequality(JSType that) { UnionTypeBuilder thisRestricted = new UnionTypeBuilder(registry); UnionTypeBuilder thatRestricted = new UnionTypeBuilder(registry); for (JSType element : alternates) { TypePair p = element.getTypesUnderInequality(that); if (p.typeA != null) { thisRestricted.addAlternate(p.typeA); } if (p.typeB != null) { thatRestricted.addAlternate(p.typeB); } } return new TypePair( thisRestricted.build(), thatRestricted.build()); } @Override public TypePair getTypesUnderShallowInequality(JSType that) { UnionTypeBuilder thisRestricted = new UnionTypeBuilder(registry); UnionTypeBuilder thatRestricted = new UnionTypeBuilder(registry); for (JSType element : alternates) { TypePair p = element.getTypesUnderShallowInequality(that); if (p.typeA != null) { thisRestricted.addAlternate(p.typeA); } if (p.typeB != null) { thatRestricted.addAlternate(p.

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>typeB); } } return new TypePair( thisRestricted.build(), thatRestricted.build()); } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseUnionType(this); } @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) { setResolvedTypeInternal(this); // for circularly defined types. boolean changed = false; ImmutableList.Builder<JSType> resolvedTypes = ImmutableList.builder(); for (JSType alternate : alternates) { JSType newAlternate = alternate.resolve(t, scope); changed |= (alternate != newAlternate); resolvedTypes.add(alternate); } if (changed) { Collection<JSType> newAlternates = resolvedTypes.build(); Preconditions.checkState( newAlternates.hashCode() == this.hashcode); alternates = newAlternates; } return this; } @Override public String toDebugHashCodeString() { List<String> hashCodes = Lists.newArrayList(); for (JSType a : alternates) { hashCodes.add(a.toDebugHashCodeString()); } return "{(" + Joiner.on(",").join(hashCodes) + ")}"; } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> } else { return getNativeType(JSTypeNative.NO_TYPE); } } public JSType caseAllType() { return getNativeType(JSTypeNative.NO_OBJECT_TYPE); } public JSType caseVoidType() { return getNativeType(JSTypeNative.NO_OBJECT_TYPE); } public JSType caseEnumElementType(EnumElementType type) { return type.getPrimitiveType().visit(this); } } NoObjectType(JSTypeRegistry registry) { super(registry, null, null, registry.createArrowType(null, null), null, null, true, true); getInternalArrowType().returnType = this; this.setInstanceType(this); } @Override public TernaryValue testForEquality(JSType that) { return that.isEmptyType() ? TernaryValue.TRUE : TernaryValue.UNKNOWN; } @Override public boolean isSubtype(JSType that) { if (JSType.isSubtype(this, that)) { return true; } else { return that.isObject() && !that.isNoType(); } } @Override public boolean isFunctionType() { return false; } @Override public boolean isNoObjectType() { return true; } @Override public JSType getLeastSupertype(JSType that) { return that.visit(leastSupertypeVisitor); } @Override public JSType getGreatestSubtype(JSType that) { return that.visit(greatestSubtypeVisitor); } @Override public ObjectType getImplicitPrototype() { return null; } @Override public String getReferenceName() { return null; } @Override public boolean matchesNumberContext() { return true; } @Override public boolean matchesObjectContext() { return true; } @Override public boolean matchesStringContext() { return true; } @Override public boolean isEquivalentTo(JSType that) { return this == that; } @Override public int hashCode() { return System.identityHashCode(this); } @Override public int getPropertiesCount() { // Should never be called, returning the biggest number to highlight the // 'unifying'

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> role of this type. return Integer.MAX_VALUE; } @Override public JSType getPropertyType(String propertyName) { // Return the least type to be a proper subtype of all other objects. return getNativeType(JSTypeNative.NO_TYPE); } @Override public boolean hasProperty(String propertyName) { // has all properties, since it is any object return true; } @Override boolean defineProperty(String propertyName, JSType type, boolean inferred, boolean inExterns) { // nothing, all properties are defined return true; } @Override public JSDocInfo getOwnPropertyJSDocInfo(String propertyName) { return null; } @Override public void setPropertyJSDocInfo(String propertyName, JSDocInfo info, boolean inExterns) { // Do nothing, specific properties do not have JSDocInfo. } @Override public boolean isPropertyTypeInferred(String propertyName) { return false; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseNoObjectType(); } @Override public String toString() { return "NoObject"; } @Override public FunctionType getConstructor() { return null; } @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) { return this; } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>"; if (d == Double.NEGATIVE_INFINITY) return "-Infinity"; if (d == 0.0) return "0"; if ((base < 2) || (base > 36)) { throw Context.reportRuntimeError1( "msg.bad.radix", Integer.toString(base)); } if (base != 10) { return DToA.JS_dtobasestr(base, d); } else { StringBuffer result = new StringBuffer(); DToA.JS_dtostr(result, DToA.DTOSTR_STANDARD, 0, d); return result.toString(); } } /** * If str is a decimal presentation of Uint32 value, return it as long. * Othewise return -1L; */ public static long testUint32String(String str) { // The length of the decimal string representation of // UINT32_MAX_VALUE, 4294967296 final int MAX_VALUE_LENGTH = 10; int len = str.length(); if (1 <= len && len <= MAX_VALUE_LENGTH) { int c = str.charAt(0); c -= '0'; if (c == 0) { // Note that 00,01 etc. are not valid Uint32 presentations return (len == 1) ? 0L : -1L; } if (1 <= c && c <= 9) { long v = c; for (int i = 1; i != len; ++i) { c = str.charAt(i) - '0'; if (!(0 <= c && c <= 9)) { return -1; } v = 10 * v + c; } // Check for overflow if ((v >>> 32) == 0) { return v; } } } return -1; } static boolean isSpecialProperty(String s) { return s.equals("__proto__") || s.equals("__parent__"); } // ------------------ // Statements // ------------------ public static String getMessage0(String messageId) { return getMessage(messageId, null);

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>/* * Copyright 2007 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.jstype.FunctionType; import com.google.javascript.rhino.jstype.JSTypeRegistry; import com.google.javascript.rhino.jstype.ObjectType; import java.util.Collection; import java.util.Collections; import java.util.List; /** * CodingConvention defines a set of hooks to customize the behavior of the * Compiler for a specific team/company. * * * */ public class DefaultCodingConvention implements CodingConvention { @Override public boolean isConstant(String variableName) { return false; } @Override public boolean isConstantKey(String variableName) { return false; } @Override public boolean isValidEnumKey(String key) { return key != null && key.length() > 0; } @Override public boolean isOptionalParameter(Node parameter) { // be as lax as possible, but this must be mutually exclusive from // var_args parameters. return !isVarArgsParameter(parameter); } @Override public boolean isVarArgsParameter(Node parameter) { // be as lax as possible return parameter.getParent().getLastChild() == parameter; } @Override public boolean isExported(String name, boolean local) { return local && name.startsWith("$super"); } @Override public boolean isExported(String name) { return isExported(name, false) || isExported(name, true); } @

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>Override public boolean isPrivate(String name) { return false; } @Override public SubclassRelationship getClassesDefinedByCall(Node callNode) { return null; } @Override public boolean isSuperClassReference(String propertyName) { return false; } @Override public String extractClassNameIfProvide(Node node, Node parent) { String message = "only implemented in GoogleCodingConvention"; throw new UnsupportedOperationException(message); } @Override public String extractClassNameIfRequire(Node node, Node parent) { String message = "only implemented in GoogleCodingConvention"; throw new UnsupportedOperationException(message); } @Override public String getExportPropertyFunction() { return null; } @Override public String getExportSymbolFunction() { return null; } @Override public List<String> identifyTypeDeclarationCall(Node n) { return null; } @Override public String identifyTypeDefAssign(Node n) { return null; } @Override public void applySubclassRelationship(FunctionType parentCtor, FunctionType childCtor, SubclassType type) { // do nothing } @Override public String getAbstractMethodName() { return null; } @Override public String getSingletonGetterClassName(Node callNode) { return null; } @Override public void applySingletonGetter(FunctionType functionType, FunctionType getterType, ObjectType objectType) { // do nothing. } @Override public DelegateRelationship getDelegateRelationship(Node callNode) { return null; } @Override public void applyDelegateRelationship( ObjectType delegateSuperclass, ObjectType delegateBase, ObjectType delegator, FunctionType delegateProxy, FunctionType findDelegate) { // do nothing. } @Override public String getDelegateSuperclassName() { return null; } @Override public void defineDelegateProxyPrototypeProperties( JSTypeRegistry registry, Scope scope, List<ObjectType> delegateProxyPrototypes) { // do nothing. } @Override public String getGlobalObject() { return "window"; } @Override public boolean isPropertyTestFunction(Node call) { return false; } @Override public ObjectLiteralCast getObjectLiteralCast(NodeTraversal t, Node callNode) {

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> return null; } @Override public Collection<AssertionFunctionSpec> getAssertionFunctions() { return Collections.emptySet(); } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> fileName, Generator generator) { return new JSSourceFile(SourceFile.fromGenerator(fileName, generator)); } private SourceFile referenced; private JSSourceFile(SourceFile referenced) { super(referenced.getName()); this.referenced = referenced; } @Override public String getCode() throws IOException { return referenced.getCode(); } @Override public void clearCachedSource() { referenced.clearCachedSource(); } @Override @VisibleForTesting String getCodeNoCache() { return referenced.getCodeNoCache(); } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> this.newNodes = newNodes; } public boolean apply(Node n) { if (!n.isQualifiedName()) { return false; } Node current; for (current = n; current.getType() == Token.GETPROP; current = current.getFirstChild()) { if (newNodes.contains(current)) { return true; } } return current.getType() == Token.NAME && newNodes.contains(current); } } /** * Builds the namespace lazily. */ private void process() { if (externsRoot != null) { inExterns = true; NodeTraversal.traverse(compiler, externsRoot, new BuildGlobalNamespace()); } inExterns = false; NodeTraversal.traverse(compiler, root, new BuildGlobalNamespace()); generated = true; } /** * Determines whether a name reference in a particular scope is a global name * reference. * * @param name A variable or property name (e.g. "a" or "a.b.c.d") * @param s The scope in which the name is referenced * @return Whether the name reference is a global name reference */ private boolean isGlobalNameReference(String name, Scope s) { String topVarName = getTopVarName(name); return isGlobalVarReference(topVarName, s); } /** * Gets the top variable name from a possibly namespaced name. * * @param name A variable or qualified property name (e.g. "a" or "a.b.c.d") * @return The top variable name (e.g. "a") */ private String getTopVarName(String name) { int firstDotIndex = name.indexOf('.'); return firstDotIndex == -1 ? name : name.substring(0, firstDotIndex); } /** * Determines whether a variable name reference in a particular scope is a * global variable reference. * * @param name A variable name (e.g. "a") * @param s The scope in which the name is referenced * @return Whether the name reference is a global variable reference */ private boolean isGlobalVarReference(String name, Scope s) { Scope.Var

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> v = s.getVar(name); if (v == null && externsScope != null) { v = externsScope.getVar(name); } return v != null && !v.isLocal(); } /** * Gets whether a scope is the global scope. * * @param s A scope * @return Whether the scope is the global scope */ private boolean isGlobalScope(Scope s) { return s.getParent() == null; } // ------------------------------------------------------------------------- /** * Builds a tree representation of the global namespace. Omits prototypes. */ private class BuildGlobalNamespace extends AbstractPostOrderCallback { private final Predicate<Node> nodeFilter; BuildGlobalNamespace() { this(null); } /** * Builds a global namepsace, but only visits nodes that match the * given filter. */ BuildGlobalNamespace(Predicate<Node> nodeFilter) { this.nodeFilter = nodeFilter; } @Override public void visit(NodeTraversal t, Node n, Node parent) { if (nodeFilter != null && !nodeFilter.apply(n)) { return; } // If we are traversing the externs, then we save a pointer to the scope // generated by them, so that we can do lookups in it later. if (externsRoot != null && n == externsRoot) { externsScope = t.getScope(); } String name; boolean isSet = false; Name.Type type = Name.Type.OTHER; boolean isPropAssign = false; switch (n.getType()) { case Token.STRING: // This may be a key in an object literal declaration. name = null; if (parent != null && parent.getType() == Token.OBJECTLIT) { name = getNameForObjLitKey(n); } if (name == null) return; isSet = true; type = getValueType(n.getNext()); break; case Token.NAME: // This may be a variable get or set. if (parent != null) { switch (parent.getType()) { case Token.VAR: isSet = true; Node rvalue = n.getFirstChild(); type = rvalue == null ? Name.Type.OTHER : getValueType(

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>.Type.ALIASING_GET); nameObj.addRef(get); Ref.markTwins(set, get); } else if (isConstructorOrEnumDeclaration(n, parent)) { // Names with a @constructor or @enum annotation are always collapsed nameObj.setIsClassOrEnum(); } } /** * Determines whether a set operation is a constructor or enumeration * declaration. The set operation may either be an assignment to a name, * a variable declaration, or an object literal key mapping. * * @param n The node that represents the name being set * @param parent Parent node of {@code n} (an ASSIGN, VAR, or OBJLIT node) * @return Whether the set operation is either a constructor or enum * declaration */ private boolean isConstructorOrEnumDeclaration(Node n, Node parent) { JSDocInfo info; int valueNodeType; switch (parent.getType()) { case Token.ASSIGN: info = parent.getJSDocInfo(); valueNodeType = n.getNext().getType(); break; case Token.VAR: info = n.getJSDocInfo(); if (info == null) { info = parent.getJSDocInfo(); } Node valueNode = n.getFirstChild(); valueNodeType = valueNode != null ? valueNode.getType() : Token.VOID; break; default: return false; } // Heed the annotations only if they're sensibly used. return info != null && (info.isConstructor() && valueNodeType == Token.FUNCTION || info.hasEnumParameterType() && valueNodeType == Token.OBJECTLIT); } /** * Updates our respresentation of the global namespace to reflect an * assignment to a global name in a local scope. * * @param t The traversal * @param n The node currently being visited * @param parent {@code n}'s parent * @param name The global name (e.g. "a" or "a.b.c.d") */ void handleSetFromLocal(NodeTraversal t, Node n, Node parent, String name) { if (maybeHandlePrototypePrefix(t, n, parent, name)) return; Name node = getOrCreateName(name);

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> Ref set = new Ref(t, n, Ref.Type.SET_FROM_LOCAL); node.addRef(set); if (isNestedAssign(parent)) { // This assignment is both a set and a get that creates an alias. Ref get = new Ref(t, n, Ref.Type.ALIASING_GET); node.addRef(get); Ref.markTwins(set, get); } } /** * Updates our respresentation of the global namespace to reflect a read * of a global name. * * @param t The traversal * @param n The node currently being visited * @param parent {@code n}'s parent * @param name The global name (e.g. "a" or "a.b.c.d") */ void handleGet(NodeTraversal t, Node n, Node parent, String name) { if (maybeHandlePrototypePrefix(t, n, parent, name)) return; Ref.Type type = Ref.Type.DIRECT_GET; if (parent != null) { switch (parent.getType()) { case Token.IF: case Token.TYPEOF: case Token.VOID: case Token.NOT: case Token.BITNOT: case Token.POS: case Token.NEG: break; case Token.CALL: type = n == parent.getFirstChild() ? Ref.Type.CALL_GET : Ref.Type.ALIASING_GET; break; case Token.NEW: type = n == parent.getFirstChild() ? Ref.Type.DIRECT_GET : Ref.Type.ALIASING_GET; break; case Token.OR: case Token.AND: // This node is x or y in (x||y) or (x&&y). We only know that an // alias is not getting created for this name if the result is used // in a boolean context or assigned to the same name // (e.g. var a = a || {}). type = determineGetTypeForHookOrBooleanExpr(t, parent, name); break; case Token.HOOK: if (n != parent.getFirstChild()) { // This node is y or z in (x?y:z). We only know that an alias is

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> // not getting created for this name if the result is assigned to // the same name (e.g. var a = a ? a : {}). type = determineGetTypeForHookOrBooleanExpr(t, parent, name); } break; default: type = Ref.Type.ALIASING_GET; break; } } handleGet(t, n, parent, name, type); } /** * Determines whether the result of a hook (x?y:z) or boolean expression * (x||y) or (x&&y) is assigned to a specific global name. * * @param t The traversal * @param parent The parent of the current node in the traversal. This node * should already be known to be a HOOK, AND, or OR node. * @param name A name that is already known to be global in the current * scope (e.g. "a" or "a.b.c.d") * @return The expression's get type, either {@link Ref.Type#DIRECT_GET} or * {@link Ref.Type#ALIASING_GET} */ Ref.Type determineGetTypeForHookOrBooleanExpr( NodeTraversal t, Node parent, String name) { Node prev = parent; for (Node anc : parent.getAncestors()) { switch (anc.getType()) { case Token.EXPR_RESULT: case Token.VAR: case Token.IF: case Token.WHILE: case Token.FOR: case Token.TYPEOF: case Token.VOID: case Token.NOT: case Token.BITNOT: case Token.POS: case Token.NEG: return Ref.Type.DIRECT_GET; case Token.HOOK: if (anc.getFirstChild() == prev) { return Ref.Type.DIRECT_GET; } break; case Token.ASSIGN: if (!name.equals(anc.getFirstChild().getQualifiedName())) { return Ref.Type.ALIASING_GET; } break; case Token.NAME: // a variable declaration if (!name.equals(anc.getString())) { return Ref.Type.ALIASING_GET; } break; case Token.CALL: if (anc.getFirst

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> ancestor = ancestor.parent) { ancestor.hasClassOrEnumDescendant = true; } } /** * Determines whether this name is a prefix of at least one class or enum * name. Because classes and enums are always collapsed, the namespace will * have different properties in compiled code than in uncompiled code. * * For example, if foo.bar.DomHelper is a class, then foo and foo.bar are * considered namespaces. */ boolean isNamespace() { return hasClassOrEnumDescendant && type == Type.OBJECTLIT; } /** * Determines whether this is a simple name (as opposed to a qualified * name). */ boolean isSimpleName() { return parent == null; } @Override public String toString() { return fullName() + " (" + type + "): globalSets=" + globalSets + ", localSets=" + localSets + ", totalGets=" + totalGets + ", aliasingGets=" + aliasingGets + ", callGets=" + callGets; } String fullName() { return parent == null ? name : parent.fullName() + '.' + name; } /** * Tries to get the doc info for a given declaration ref. */ private static JSDocInfo getDocInfoForDeclaration(Ref ref) { if (ref.node != null) { Node refParent = ref.node.getParent(); switch (refParent.getType()) { case Token.FUNCTION: case Token.ASSIGN: return refParent.getJSDocInfo(); case Token.VAR: return ref.node == refParent.getFirstChild() ? refParent.getJSDocInfo() : ref.node.getJSDocInfo(); } } return null; } } // ------------------------------------------------------------------------- /** * A global name reference. Contains references to the relevant parse tree * node and its ancestors that may be affected. */ static class Ref { enum Type { SET_FROM_GLOBAL, SET_FROM_LOCAL, PROTOTYPE_GET, ALIASING_GET, // Prevents a name's properties from being collapsed DIRECT_GET, // Prevents a name from being completely eliminated CALL_GET, // Prevents a name from being collapsed if never set

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>Compiler compiler; public CompilerInput(SourceAst ast) { this(ast, ast.getSourceFile().getName(), false); } public CompilerInput(SourceAst ast, boolean isExtern) { this(ast, ast.getSourceFile().getName(), isExtern); } public CompilerInput(SourceAst ast, String inputName, boolean isExtern) { this.ast = ast; this.name = inputName; this.isExtern = isExtern; } public CompilerInput(JSSourceFile file) { this(file, false); } public CompilerInput(JSSourceFile file, boolean isExtern) { this.ast = new JsAst(file); this.name = file.getName(); this.isExtern = isExtern; } /** Returns a name for this input. Must be unique across all inputs. */ @Override public String getName() { return name; } /** Gets the path relative to closure-base, if one is available. */ @Override public String getPathRelativeToClosureBase() { // TODO(nicksantos): Implement me. throw new UnsupportedOperationException(); } @Override public Node getAstRoot(AbstractCompiler compiler) { return ast.getAstRoot(compiler); } @Override public void clearAst() { ast.clearAst(); } @Override public SourceFile getSourceFile() { return ast.getSourceFile(); } @Override public void setSourceFile(SourceFile file) { ast.setSourceFile(file); } /** Returns the SourceAst object on which this input is based. */ public SourceAst getSourceAst() { return ast; } /** Sets an error manager for routing error messages. */ public void setErrorManager(ErrorManager errorManager) { this.errorManager = errorManager; } /** Sets an abstract compiler for doing parsing. */ public void setCompiler(AbstractCompiler compiler) { this.compiler = compiler; setErrorManager(compiler.getErrorManager()); } /** Gets a list of types depended on by this input. */ @Override public Collection<String> getRequires() { Preconditions.checkNotNull(errorManager, "Expected setErrorManager to be called first"); try { regenerateDependencyInfoIf

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>Necessary(); return Collections.<String>unmodifiableSet(requires); } catch (IOException e) { errorManager.report(CheckLevel.ERROR, JSError.make(AbstractCompiler.READ_ERROR, getName())); return ImmutableList.<String>of(); } } /** Gets a list of types provided by this input. */ @Override public Collection<String> getProvides() { Preconditions.checkNotNull(errorManager, "Expected setErrorManager to be called first"); try { regenerateDependencyInfoIfNecessary(); return Collections.<String>unmodifiableSet(provides); } catch (IOException e) { errorManager.report(CheckLevel.ERROR, JSError.make(AbstractCompiler.READ_ERROR, getName())); return ImmutableList.<String>of(); } } /** * Regenerates the provides/requires if we need to do so. */ private void regenerateDependencyInfoIfNecessary() throws IOException { // If the code is NOT a JsAst, then it was not originally JS code. // Look at the Ast for dependency info. if (!(ast instanceof JsAst)) { Preconditions.checkNotNull(compiler, "Expected setCompiler to be called first"); DepsFinder finder = new DepsFinder(); Node root = getAstRoot(compiler); if (root == null) { return; } finder.visitTree(getAstRoot(compiler)); // TODO(nicksantos|user): This caching behavior is a bit // odd, and only works if you assume the exact call flow that // clients are currently using. In that flow, they call // getProvides(), then remove the goog.provide calls from the // AST, and then call getProvides() again. // // This won't work for any other call flow, or any sort of incremental // compilation scheme. The API needs to be fixed so callers aren't // doing weird things like this, and then we should get rid of the // multiple-scan strategy. provides.addAll(finder.provides); requires.addAll(finder.requires); } else { // Otherwise, look at the source code. if (!generatedDependencyInfoFromSource) { // Note: it's ok to use getName() instead of // getPathRelativeToClosureBase() here because we're not using //

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> compiler. * * This is a preferred internal constructor. */ private JSError(String sourceName, int lineno, int charno, DiagnosticType type, CheckLevel level, String... arguments) { this.type = type; this.description = type.format.format(arguments); this.lineNumber = lineno; this.charno = charno; this.sourceName = sourceName; this.level = level == null ? type.level : level; } /** * Creates a JSError for a source file location. Package private to avoid * any entanglement with code outside of the compiler. * * This is a preferred internal constructor. */ private JSError(String sourceName, Node node, DiagnosticType type, String... arguments) { this(sourceName, (node != null) ? node.getLineno() : -1, (node != null) ? node.getCharno() : -1, type, null, arguments); } public DiagnosticType getType() { return type; } /** * Format a message at the given level. * * @return the formatted message or {@code null} */ public String format(CheckLevel level, MessageFormatter formatter) { switch (level) { case ERROR: return formatter.formatError(this); case WARNING: return formatter.formatWarning(this); default: return null; } } @Override public String toString() { // TODO(user): remove custom toString. return type.key + ". " + description + " at " + (sourceName != null && sourceName.length() > 0 ? sourceName : "(unknown source)") + " line " + (lineNumber != -1 ? String.valueOf(lineNumber) : "(unknown line)") + " : " + (charno != -1 ? String.valueOf(charno) : "(unknown column)"); } /** * Get the character number. */ public int getCharno() { return charno; } @Override public boolean equals(Object o) { // Generated by Intellij IDEA if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>; } JSError jsError = (JSError) o; if (charno != jsError.charno) { return false; } if (lineNumber != jsError.lineNumber) { return false; } if (!description.equals(jsError.description)) { return false; } if (level != jsError.level) { return false; } if (sourceName != null ? !sourceName.equals(jsError.sourceName) : jsError.sourceName != null) { return false; } if (!type.equals(jsError.type)) { return false; } return true; } @Override public int hashCode() { // Generated by Intellij IDEA int result = type.hashCode(); result = 31 * result + description.hashCode(); result = 31 * result + (sourceName != null ? sourceName.hashCode() : 0); result = 31 * result + lineNumber; result = 31 * result + level.hashCode(); result = 31 * result + charno; return result; } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> abstract T processSwitchCase(SwitchCase caseNode); abstract T processSwitchStatement(SwitchStatement statementNode); abstract T processThrowStatement(ThrowStatement statementNode); abstract T processTryStatement(TryStatement statementNode); abstract T processUnaryExpression(UnaryExpression exprNode); abstract T processVariableDeclaration(VariableDeclaration declarationNode); abstract T processVariableInitializer(VariableInitializer initializerNode); abstract T processWhileLoop(WhileLoop loopNode); abstract T processWithStatement(WithStatement statementNode); abstract T processIllegalToken(AstNode node); public T process(AstNode node) { switch (node.getType()) { case Token.ADD: case Token.AND: case Token.BITAND: case Token.BITOR: case Token.BITXOR: case Token.COMMA: case Token.DIV: case Token.EQ: case Token.GE: case Token.GT: case Token.IN: case Token.INSTANCEOF: case Token.LE: case Token.LSH: case Token.LT: case Token.MOD: case Token.MUL: case Token.NE: case Token.OR: case Token.RSH: case Token.SHEQ: case Token.SHNE: case Token.SUB: case Token.URSH: return processInfixExpression((InfixExpression) node); case Token.ARRAYLIT: return processArrayLiteral((ArrayLiteral) node); case Token.ASSIGN: case Token.ASSIGN_ADD: case Token.ASSIGN_BITAND: case Token.ASSIGN_BITOR: case Token.ASSIGN_BITXOR: case Token.ASSIGN_DIV: case Token.ASSIGN_LSH: case Token.ASSIGN_MOD: case Token.ASSIGN_MUL: case Token.ASSIGN_RSH: case Token.ASSIGN_SUB: case Token.ASSIGN_URSH: return processAssignment((Assignment) node); case Token.BITNOT: case Token.DEC: case Token.DELPROP: case Token.INC: case Token.NEG: case Token.NOT: case Token.POS: case Token.TYPEOF: case Token.VOID: return processUnaryExpression((UnaryExpression) node); case Token.BLOCK: if (node instanceof Block

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> * Gets the boolean value of a node that represents a literal. This method * effectively emulates the <code>Boolean()</code> JavaScript cast function. * * @throws IllegalArgumentException If {@code n} is not a literal value */ static TernaryValue getBooleanValue(Node n) { switch (n.getType()) { case Token.STRING: return TernaryValue.forBoolean(n.getString().length() > 0); case Token.NUMBER: return TernaryValue.forBoolean(n.getDouble() != 0); case Token.NULL: case Token.FALSE: case Token.VOID: return TernaryValue.FALSE; case Token.NAME: String name = n.getString(); if ("undefined".equals(name) || "NaN".equals(name)) { // We assume here that programs don't change the value of the keyword // undefined to something other than the value undefined. return TernaryValue.FALSE; } else if ("Infinity".equals(name)) { return TernaryValue.TRUE; } break; case Token.TRUE: case Token.ARRAYLIT: case Token.OBJECTLIT: case Token.REGEXP: return TernaryValue.TRUE; } return TernaryValue.UNKNOWN; } /** * Gets the value of a node as a String, or null if it cannot be converted. * When it returns a non-null String, this method effectively emulates the * <code>String()</code> JavaScript cast function. */ static String getStringValue(Node n) { // TODO(user): Convert constant array, object, and regex literals as well. switch (n.getType()) { case Token.NAME: case Token.STRING: return n.getString(); case Token.NUMBER: double value = n.getDouble(); long longValue = (long) value; // Return "1" instead of "1.0" if (longValue == value) { return Long.toString(longValue); } else { return Double.toString(n.getDouble()); } case Token.FALSE: case Token.TRUE: case Token.NULL: return Node.tokenToName(n.getType()); case Token.VOID: return "undefined"; } return null;

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> } /** * Gets the function's name. This method recognizes five forms: * <ul> * <li>{@code function name() ...}</li> * <li>{@code var name = function() ...}</li> * <li>{@code qualified.name = function() ...}</li> * <li>{@code var name2 = function name1() ...}</li> * <li>{@code qualified.name2 = function name1() ...}</li> * </ul> * In two last cases with named function expressions, the second name is * returned (the variable of qualified name). * * @param n a node whose type is {@link Token#FUNCTION} * @return the function's name, or {@code null} if it has no name */ static String getFunctionName(Node n) { Node parent = n.getParent(); String name = n.getFirstChild().getString(); switch (parent.getType()) { case Token.NAME: // var name = function() ... // var name2 = function name1() ... return parent.getString(); case Token.ASSIGN: // qualified.name = function() ... // qualified.name2 = function name1() ... return parent.getFirstChild().getQualifiedName(); default: // function name() ... return name != null && name.length() != 0 ? name : null; } } /** * Returns true if this is an immutable value. */ static boolean isImmutableValue(Node n) { switch (n.getType()) { case Token.STRING: case Token.NUMBER: case Token.NULL: case Token.TRUE: case Token.FALSE: case Token.VOID: return true; case Token.NEG: return isImmutableValue(n.getFirstChild()); case Token.NAME: String name = n.getString(); // We assume here that programs don't change the value of the keyword // undefined to something other than the value undefined. return "undefined".equals(name) || "Infinity".equals(name) || "NaN".equals(name); } return false; } /** * Returns true if this is a literal value. We define a literal value * as any node that evaluates to the same thing regardless of when or

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>-effects (unlike '+='), and has no * conditional aspects (unlike '||'). */ static boolean isSimpleOperatorType(int type) { switch (type) { case Token.ADD: case Token.BITAND: case Token.BITNOT: case Token.BITOR: case Token.BITXOR: case Token.COMMA: case Token.DIV: case Token.EQ: case Token.GE: case Token.GETELEM: case Token.GETPROP: case Token.GT: case Token.INSTANCEOF: case Token.LE: case Token.LSH: case Token.LT: case Token.MOD: case Token.MUL: case Token.NE: case Token.NOT: case Token.RSH: case Token.SHEQ: case Token.SHNE: case Token.SUB: case Token.TYPEOF: case Token.VOID: case Token.POS: case Token.NEG: case Token.URSH: return true; default: return false; } } /** * Creates an EXPR_RESULT. * * @param child The expression itself. * @return Newly created EXPR node with the child as subexpression. */ public static Node newExpr(Node child) { Node expr = new Node(Token.EXPR_RESULT, child) .copyInformationFrom(child); return expr; } /** * Returns true if the node may create new mutable state, or change existing * state. * * @see <a href="http://www.xkcd.org/326/">XKCD Cartoon</a> */ static boolean mayEffectMutableState(Node n) { return mayEffectMutableState(n, null); } static boolean mayEffectMutableState(Node n, AbstractCompiler compiler) { return checkForStateChangeHelper(n, true, compiler); } /** * Returns true if the node which may have side effects when executed. */ static boolean mayHaveSideEffects(Node n) { return mayHaveSideEffects(n, null); } static boolean mayHaveSideEffects(Node n, AbstractCompiler compiler) { return checkForStateChangeHelper(n, false, compiler); }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>2 conditional ?: * 3 logical-or || * 4 logical-and && * 5 bitwise-or | * 6 bitwise-xor ^ * 7 bitwise-and & * 8 equality == != * 9 relational < <= > >= * 10 bitwise shift << >> >>> * 11 addition/subtraction + - * 12 multiply/divide * / % * 13 negation/increment ! ~ - ++ -- * 14 call, member () [] . */ static int precedence(int type) { switch (type) { case Token.COMMA: return 0; case Token.ASSIGN_BITOR: case Token.ASSIGN_BITXOR: case Token.ASSIGN_BITAND: case Token.ASSIGN_LSH: case Token.ASSIGN_RSH: case Token.ASSIGN_URSH: case Token.ASSIGN_ADD: case Token.ASSIGN_SUB: case Token.ASSIGN_MUL: case Token.ASSIGN_DIV: case Token.ASSIGN_MOD: case Token.ASSIGN: return 1; case Token.HOOK: return 2; // ?: operator case Token.OR: return 3; case Token.AND: return 4; case Token.BITOR: return 5; case Token.BITXOR: return 6; case Token.BITAND: return 7; case Token.EQ: case Token.NE: case Token.SHEQ: case Token.SHNE: return 8; case Token.LT: case Token.GT: case Token.LE: case Token.GE: case Token.INSTANCEOF: case Token.IN: return 9; case Token.LSH: case Token.RSH: case Token.URSH: return 10; case Token.SUB: case Token.ADD: return 11; case Token.MUL: case Token.MOD: case Token.DIV: return 12; case Token.INC: case Token.DEC: case Token.NEW: case Token.DELPROP: case Token.TYPEOF: case Token.VOID: case Token.NOT

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>BITOR: return "|"; case Token.OR: return "||"; case Token.BITXOR: return "^"; case Token.AND: return "&&"; case Token.BITAND: return "&"; case Token.SHEQ: return "==="; case Token.EQ: return "=="; case Token.NOT: return "!"; case Token.NE: return "!="; case Token.SHNE: return "!=="; case Token.LSH: return "<<"; case Token.IN: return "in"; case Token.LE: return "<="; case Token.LT: return "<"; case Token.URSH: return ">>>"; case Token.RSH: return ">>"; case Token.GE: return ">="; case Token.GT: return ">"; case Token.MUL: return "*"; case Token.DIV: return "/"; case Token.MOD: return "%"; case Token.BITNOT: return "~"; case Token.ADD: return "+"; case Token.SUB: return "-"; case Token.POS: return "+"; case Token.NEG: return "-"; case Token.ASSIGN: return "="; case Token.ASSIGN_BITOR: return "|="; case Token.ASSIGN_BITXOR: return "^="; case Token.ASSIGN_BITAND: return "&="; case Token.ASSIGN_LSH: return "<<="; case Token.ASSIGN_RSH: return ">>="; case Token.ASSIGN_URSH: return ">>>="; case Token.ASSIGN_ADD: return "+="; case Token.ASSIGN_SUB: return "-="; case Token.ASSIGN_MUL: return "*="; case Token.ASSIGN_DIV: return "/="; case Token.ASSIGN_MOD: return "%="; case Token.VOID: return "void"; case Token.TYPEOF: return "typeof"; case Token.INSTANCEOF: return "instanceof"; default: return null; } } /** * Converts an operator's token value (see {@link Token}) to a string * representation or fails. * * @param operator the operator's token value to convert * @return the string representation * @throws Error if the token value is not an operator */ static String op

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> } private static class VarCollector implements Visitor { final Map<String, Node> vars = Maps.newLinkedHashMap(); public void visit(Node n) { if (n.getType() == Token.NAME) { Node parent = n.getParent(); if (parent != null && parent.getType() == Token.VAR) { String name = n.getString(); if (!vars.containsKey(name)) { vars.put(name, n); } } } } } /** * Retrieves vars declared in the current node tree, excluding descent scopes. */ public static Collection<Node> getVarsDeclaredInBranch(Node root) { VarCollector collector = new VarCollector(); visitPreOrder( root, collector, new MatchNotFunction()); return collector.vars.values(); } /** * @return {@code true} if the node an assignment to a prototype property of * some constructor. */ static boolean isPrototypePropertyDeclaration(Node n) { if (!isExprAssign(n)) { return false; } return isPrototypeProperty(n.getFirstChild().getFirstChild()); } static boolean isPrototypeProperty(Node n) { String lhsString = n.getQualifiedName(); if (lhsString == null) { return false; } int prototypeIdx = lhsString.indexOf(".prototype."); return prototypeIdx != -1; } /** * @return The class name part of a qualified prototype name. */ static Node getPrototypeClassName(Node qName) { Node cur = qName; while (isGetProp(cur)) { if (cur.getLastChild().getString().equals("prototype")) { return cur.getFirstChild(); } else { cur = cur.getFirstChild(); } } return null; } /** * @return The string property name part of a qualified prototype name. */ static String getPrototypePropertyName(Node qName) { String qNameStr = qName.getQualifiedName(); int prototypeIdx = qNameStr.lastIndexOf(".prototype."); int memberIndex = prototypeIdx + ".prototype".length() + 1; return qNameStr.substring(memberIndex); } /** * Create a node for an empty result expression: * "void

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>0" */ static Node newUndefinedNode(Node srcReferenceNode) { // TODO(johnlenz): Why this instead of the more common "undefined"? Node node = new Node(Token.VOID, Node.newNumber(0)); if (srcReferenceNode != null) { node.copyInformationFromForTree(srcReferenceNode); } return node; } /** * Create a VAR node containing the given name and initial value expression. */ static Node newVarNode(String name, Node value) { Node nodeName = Node.newString(Token.NAME, name); if (value != null) { Preconditions.checkState(value.getNext() == null); nodeName.addChildToBack(value); nodeName.copyInformationFrom(value); } Node var = new Node(Token.VAR, nodeName) .copyInformationFrom(nodeName); return var; } /** * A predicate for matching name nodes with the specified node. */ private static class MatchNameNode implements Predicate<Node>{ final String name; MatchNameNode(String name){ this.name = name; } public boolean apply(Node n) { return n.getType() == Token.NAME && n.getString().equals(name); } } /** * A predicate for matching nodes with the specified type. */ static class MatchNodeType implements Predicate<Node>{ final int type; MatchNodeType(int type){ this.type = type; } public boolean apply(Node n) { return n.getType() == type; } } /** * A predicate for matching var or function declarations. */ static class MatchDeclaration implements Predicate<Node> { public boolean apply(Node n) { return isFunctionDeclaration(n) || n.getType() == Token.VAR; } } /** * A predicate for matching anything except function nodes. */ static class MatchNotFunction implements Predicate<Node>{ public boolean apply(Node n) { return !isFunction(n); } } /** * A predicate for matching statements without exiting the current scope. */ static class MatchShallowStatement implements Predicate<Node>{ public boolean apply(Node n) { Node parent = n.getParent(); return n.getType() ==

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> total += getCount(c, pred, traverseChildrenPred); } } return total; } /** * Interface for use with the visit method. * @see #visit */ static interface Visitor { void visit(Node node); } /** * A pre-order traversal, calling Vistor.visit for each child matching * the predicate. */ static void visitPreOrder(Node node, Visitor vistor, Predicate<Node> traverseChildrenPred) { vistor.visit(node); if (traverseChildrenPred.apply(node)) { for (Node c = node.getFirstChild(); c != null; c = c.getNext()) { visitPreOrder(c, vistor, traverseChildrenPred); } } } /** * A post-order traversal, calling Vistor.visit for each child matching * the predicate. */ static void visitPostOrder(Node node, Visitor vistor, Predicate<Node> traverseChildrenPred) { if (traverseChildrenPred.apply(node)) { for (Node c = node.getFirstChild(); c != null; c = c.getNext()) { visitPostOrder(c, vistor, traverseChildrenPred); } } vistor.visit(node); } /** * @return Whether a TRY node has a finally block. */ static boolean hasFinally(Node n) { Preconditions.checkArgument(n.getType() == Token.TRY); return n.getChildCount() == 3; } /** * @return The BLOCK node containing the CATCH node (if any) * of a TRY. */ static Node getCatchBlock(Node n) { Preconditions.checkArgument(n.getType() == Token.TRY); return n.getFirstChild().getNext(); } /** * @return Whether BLOCK (from a TRY node) contains a CATCH. * @see NodeUtil#getCatchBlock */ static boolean hasCatchHandler(Node n) { Preconditions.checkArgument(n.getType() == Token.BLOCK); return n.hasChildren() && n.getFirstChild().getType() == Token.CATCH; } /** * @param fnNode The function. * @return The Node containing the Function parameters. */ static Node

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> * Construct a tracer whose type is based on the short name of the object * @param object Object to use as type name * @param comment A comment * @return new Tracer. */ static Tracer shortName(Object object, String comment) { if (object == null) { return new Tracer(comment); } return new Tracer(object.getClass().getSimpleName(), comment); } /** * Converts 'v' to a string and pads it with up to 16 spaces for * improved alignment. * @param v The value to convert. * @param digits_column_width The desired with of the string. */ private static String longToPaddedString(long v, int digits_column_width) { int digit_width = numDigits(v); StringBuilder sb = new StringBuilder(); appendSpaces(sb, digits_column_width - digit_width); sb.append(v); return sb.toString(); } /** * Gets the number of digits in an integer when printed in base 10. Assumes * a positive integer. * @param n The value. * @return The number of digits in the string. */ private static int numDigits(long n) { int i = 0; do { i++; n = n / 10; } while (n > 0); return i; } /** * Gets a string of spaces of the length specified. * @param sb The string builder to append to. * @param numSpaces The number of spaces in the string. */ @VisibleForTesting static void appendSpaces(StringBuilder sb, int numSpaces) { if (numSpaces > 16) { logger.warning("Tracer.appendSpaces called with large numSpaces"); // Avoid long loop in case some bug in the caller numSpaces = 16; } while (numSpaces >= 5) { sb.append(" "); numSpaces -= 5; } // We know it's less than 5 now switch (numSpaces) { case 1: sb.append(" "); break; case 2: sb.append(" "); break; case 3: sb.append

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> { long value = extraTracingStatistics.get(i).stop(startThread); extraTracingValues[i] = value - extraTracingValues[i]; } } // Do nothing if the thread trace was not initialized. if (!trace.isInitialized()) { return 0; } trace.endEvent(this, silence_threshold); return stopTimeMs - startTimeMs; } /** Stop the trace using the default silence_threshold * * @return The time that this trace actually ran. */ long stop() { return stop(-1); } @Override public String toString() { if (type == null) { return comment; } else { return "[" + type + "] " + comment; } } static void setDefaultSilenceThreshold(int threshold) { getThreadTrace().defaultSilenceThreshold = threshold; } /** * Initialize the trace associated with the current thread by clearing * out any existing trace. There shouldn't be a trace so if one is * found we log it as an error. */ static void initCurrentThreadTrace() { ThreadTrace events = getThreadTrace(); if (!events.isEmpty()) { logger.log(Level.WARNING, "Non-empty timer log:\n" + events, new Throwable()); clearThreadTrace(); // Grab a new thread trace if we find a previous non-empty ThreadTrace. events = getThreadTrace(); } // Mark the thread trace as initialized. events.init(); } static void initCurrentThreadTrace(int default_silence_threshold) { initCurrentThreadTrace(); setDefaultSilenceThreshold(default_silence_threshold); } /** * Returns a timer report similar to the one described in the class comment. * * @return The timer report as a string */ static String getCurrentThreadTraceReport() { return getThreadTrace().toString(); } /** * Logs a timer report similar to the one described in the class comment. */ static void logCurrentThreadTrace() { ThreadTrace trace = getThreadTrace(); // New threads must call Tracer.initCurrentThreadTrace() before Tracer // statistics are gathered. This is a recent change (Jun 2007) that // prevents spur

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>map != null) { map.incrementBy(t.type, t.extraTracingValues[i]); } } } if (elapsed < silenceThreshold) { stat.silent++; if (typeToSilentMap != null) { typeToSilentMap.incrementBy(t.type, 1); } } } } boolean isEmpty() { return events.size() == 0 && outstandingEvents.size() == 0; } void truncateOutstandingEvents() { isOutstandingEventsTruncated = true; outstandingEvents.clear(); } void truncateEvents() { isEventsTruncated = true; events.clear(); } /** Produces the lovely Trace seen in the class comments */ // Nullness checker does not understand that prettyPrint => indent != null @SuppressWarnings("nullness") @Override public String toString() { int numDigits = getMaxDigits(); StringBuilder sb = new StringBuilder(); long etime = -1; LinkedList<String> indent = prettyPrint ? new LinkedList<String>() : null; for (Event e : events) { if (prettyPrint && !e.isStart && !indent.isEmpty()) { indent.pop(); } sb.append(" "); if (prettyPrint) { sb.append(e.toString(etime, Joiner.on("").join(indent), numDigits)); } else { sb.append(e.toString(etime, "", 4)); } etime = e.eventTime(); sb.append('\n'); if (prettyPrint && e.isStart) { indent.push("| "); } } if (outstandingEvents.size() != 0) { long now = clock.currentTimeMillis(); sb.append(" Unstopped timers:\n"); for (Tracer t : outstandingEvents) { sb.append(" "). append(t). append(" ("). append(now - t.startTimeMs). append(" ms, started at "). append(formatTime(t.startTimeMs)). append(")\n"); } } for (String key : stats.keySet()) { Stat stat = stats.get(key); if (stat.count > 1) { sb.append(" TOTAL ").

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>/* * Copyright 2004 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; /** * Tests for PeepholeFoldConstants in isolation. Tests for the interaction of * multiple peephole passes are in PeepholeIntegrationTest. */ public class PeepholeFoldConstantsTest extends CompilerTestCase { // TODO(user): Remove this when we no longer need to do string comparison. private PeepholeFoldConstantsTest(boolean compareAsTree) { super("", compareAsTree); } public PeepholeFoldConstantsTest() { super(""); } @Override public void setUp() { enableLineNumberCheck(true); } @Override public CompilerPass getProcessor(final Compiler compiler) { CompilerPass peepholePass = new PeepholeOptimizationsPass(compiler, new PeepholeFoldConstants()); return peepholePass; } @Override protected int getNumRepetitions() { // Reduce this to 2 if we get better expression evaluators. return 2; } private void foldSame(String js) { testSame(js); } private void fold(String js, String expected) { test(js, expected); } private void fold(String js, String expected, DiagnosticType warning) { test(js, expected, warning); } // TODO(user): This is same as fold() except it uses string comparison. Any // test that needs tell us where a folding is constructing an invalid AST. private void assertResultString(String js, String expected) { PeepholeFoldConstantsTest scTest = new PeepholeFoldConstantsTest

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> n.getProp(Node.SKIP_INDEXES_PROP)); add("]"); break; case Token.LP: add("("); addList(first); add(")"); break; case Token.COMMA: Preconditions.checkState(childCount == 2); addList(first, false, context); break; case Token.NUMBER: Preconditions.checkState(childCount == 0); cc.addNumber(n.getDouble()); break; case Token.TYPEOF: case Token.VOID: case Token.NOT: case Token.BITNOT: case Token.POS: case Token.NEG: { // All of these unary operators are right-associative Preconditions.checkState(childCount == 1); cc.addOp(NodeUtil.opToStrNoFail(type), false); addExpr(first, NodeUtil.precedence(type)); break; } case Token.HOOK: { Preconditions.checkState(childCount == 3); int p = NodeUtil.precedence(type); addLeftExpr(first, p + 1, context); cc.addOp("?", true); addExpr(first.getNext(), 1); cc.addOp(":", true); addExpr(last, 1); break; } case Token.REGEXP: if (first.getType() != Token.STRING || last.getType() != Token.STRING) { throw new Error("Expected children to be strings"); } String regexp = regexpEscape(first.getString(), outputCharsetEncoder); // I only use one .add because whitespace matters if (childCount == 2) { add(regexp + last.getString()); } else { Preconditions.checkState(childCount == 1); add(regexp); } break; case Token.GET_REF: add(first); break; case Token.REF_SPECIAL: Preconditions.checkState(childCount == 1); add(first); add("."); add((String) n.getProp(Node.NAME_PROP)); break; case Token.FUNCTION: if (n.getClass() != Node.class) { throw new Error("Unexpected Node subclass."); } Preconditions.checkState

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> : TYPE_1 } is a supertype of a record type * of the form { b : TYPE_2, a : TYPE_1 } because B can be assigned to * A and matches all constraints. Similarly, a defined type can be assigned * to a record type so long as that defined type matches all property * constraints of the record type. A record type of the form { a : A, b : B } * can be assigned to a record of type { a : A }. * * */ public class RecordType extends PrototypeObjectType { private static final long serialVersionUID = 1L; private Map<String, JSType> properties = new HashMap<String, JSType>(); private boolean isFrozen = false; /** * Creates a record type. * * @param registry The type registry under which this type lives. * @param properties A map of all the properties of this record type. */ RecordType(JSTypeRegistry registry, Map<String, JSType> properties) { super(registry, null, null); for (String property : properties.keySet()) { defineDeclaredProperty(property, properties.get(property), false); } // Freeze the record type. isFrozen = true; } @Override public boolean isEquivalentTo(JSType other) { if (!(other instanceof RecordType)) { return false; } // Compare properties. RecordType otherRecord = (RecordType) other; Set<String> keySet = properties.keySet(); Map<String, JSType> otherProps = otherRecord.properties; if (!otherProps.keySet().equals(keySet)) { return false; } for (String key : keySet) { if (!otherProps.get(key).isEquivalentTo(properties.get(key))) { return false; } } return true; } @Override public ObjectType getImplicitPrototype() { return registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE); } @Override boolean defineProperty(String propertyName, JSType type, boolean inferred, boolean inExterns) { if (isFrozen) { return false; } if (!inferred) { properties.put(propertyName, type); } return super.defineProperty(propertyName,

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> type, inferred, inExterns); } @Override public JSType getLeastSupertype(JSType that) { if (!that.isRecordType()) { return super.getLeastSupertype(that); } RecordType thatRecord = (RecordType) that; RecordTypeBuilder builder = new RecordTypeBuilder(registry); // The least supertype consist of those properties of the record // type that both record types hold in common both by name and // type of the properties themselves. for (String property : properties.keySet()) { if (thatRecord.hasProperty(property) && thatRecord.getPropertyType(property).isEquivalentTo( getPropertyType(property))) { builder.addProperty(property, getPropertyType(property)); } } return builder.build(); } @Override public JSType getGreatestSubtype(JSType that) { if (that.isRecordType()) { RecordType thatRecord = (RecordType) that; RecordTypeBuilder builder = new RecordTypeBuilder(registry); // The greatest subtype consists of those *unique* properties of both // record types. If any property conflicts, then the NO_TYPE type // is returned. for (String property : properties.keySet()) { if (thatRecord.hasProperty(property) && !thatRecord.getPropertyType(property).isEquivalentTo( getPropertyType(property))) { return registry.getNativeObjectType(JSTypeNative.NO_TYPE); } builder.addProperty(property, getPropertyType(property)); } for (String property : thatRecord.properties.keySet()) { if (!hasProperty(property)) { builder.addProperty(property, thatRecord.getPropertyType(property)); } } return builder.build(); } JSType greatestSubtype = super.getGreatestSubtype(that); if (greatestSubtype.isNoObjectType() && !that.isNoObjectType()) { // In this branch, the other type is some object type. We find // the greatest subtype with the following algorithm: // 1) For each property "x" of this record type, take the union // of all classes with a property "x" with a compatible property type. // and which are a subtype of {@code that}. // 2) Take the

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> intersection of all of these unions. for (Map.Entry<String, JSType> entry : properties.entrySet()) { String propName = entry.getKey(); JSType propType = entry.getValue(); UnionTypeBuilder builder = new UnionTypeBuilder(registry); for (ObjectType alt : registry.getTypesWithProperty(propName)) { JSType altPropType = alt.getPropertyType(propName); if (altPropType != null && !alt.isEquivalentTo(this) && alt.isSubtype(that) && (propType.isUnknownType() || altPropType.isUnknownType() || altPropType.isEquivalentTo(propType))) { builder.addAlternate(alt); } } greatestSubtype = greatestSubtype.getLeastSupertype(builder.build()); } } return greatestSubtype; } @Override public boolean isRecordType() { return true; } @Override public boolean isSubtype(JSType that) { if (JSType.isSubtype(this, that)) { return true; } // Top of the record types is the empty record, or OBJECT_TYPE. if (registry.getNativeObjectType( JSTypeNative.OBJECT_TYPE).isSubtype(that)) { return true; } // A type is a subtype of a record type if it itself is a record // type and it has at least the same members as the parent record type // with the same types. if (!that.isRecordType()) { return false; } return RecordType.isSubtype(this, (RecordType) that); } /** Determines if typeA is a subtype of typeB */ static boolean isSubtype(ObjectType typeA, RecordType typeB) { // typeA is a subtype of record type typeB iff: // 1) typeA has all the properties declared in typeB. // 2) And for each property of typeB, // 2a) if the property of typeA is declared, it must be equal // to the type of the property of typeB, // 2b) otherwise, it must be a subtype of the property of typeB. // // To figure out why this is true, consider the following pseudo-code: // /** @

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>type {{a: (Object,null)}} */ var x; // /** @type {{a: !Object}} */ var y; // var z = {a: {}}; // x.a = null; // // y cannot be assigned to x, because line 4 would violate y's declared // properties. But z can be assigned to x. Even though z and y are the // same type, the properties of z are inferred--and so an assignment // to the property of z would not violate any restrictions on it. for (String property : typeB.properties.keySet()) { if (!typeA.hasProperty(property)) { return false; } JSType propA = typeA.getPropertyType(property); JSType propB = typeB.getPropertyType(property); if (!propA.isUnknownType() && !propB.isUnknownType()) { if (typeA.isPropertyTypeDeclared(property)) { if (!propA.isEquivalentTo(propB)) { return false; } } else { if (!propA.isSubtype(propB)) { return false; } } } } return true; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("{ "); int i = 0; for (String property : properties.keySet()) { if (i > 0) { sb.append(", "); } sb.append(property); sb.append(" : "); sb.append(properties.get(property).toString()); ++i; } sb.append(" }"); return sb.toString(); } @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) { for (Map.Entry<String, JSType> entry : properties.entrySet()) { JSType type = entry.getValue(); JSType resolvedType = type.resolve(t, scope); if (type != resolvedType) { properties.put(entry.getKey(), resolvedType); } } return super.resolveInternal(t, scope); } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> Create an exception with the specified detail message. * * Errors internal to the JavaScript engine will simply throw a * RuntimeException. * * @param sourceName the name of the source reponsible for the error * @param lineNumber the line number of the source * @param columnNumber the columnNumber of the source (may be zero if * unknown) * @param lineSource the source of the line containing the error (may be * null if unknown) */ EcmaError(String errorName, String errorMessage, String sourceName, int lineNumber, String lineSource, int columnNumber) { recordErrorOrigin(sourceName, lineNumber, lineSource, columnNumber); this.errorName = errorName; this.errorMessage = errorMessage; } @Override public String details() { return errorName+": "+errorMessage; } /** * Gets the name of the error. * * ECMA edition 3 defines the following * errors: EvalError, RangeError, ReferenceError, * SyntaxError, TypeError, and URIError. Additional error names * may be added in the future. * * See ECMA edition 3, 15.11.7.9. * * @return the name of the error. */ public String getName() { return errorName; } /** * Gets the message corresponding to the error. * * See ECMA edition 3, 15.11.7.10. * * @return an implemenation-defined string describing the error. */ public String getErrorMessage() { return errorMessage; } /** * @deprecated Use {@link RhinoException#sourceName()} from the super class. */ @Deprecated public String getSourceName() { return sourceName(); } /** * @deprecated Use {@link RhinoException#lineNumber()} from the super class. */ @Deprecated public int getLineNumber() { return lineNumber(); } /** * @deprecated * Use {@link RhinoException#columnNumber()} from the super class. */ @Deprecated public int getColumnNumber() { return columnNumber(); } /** * @deprecated Use {@link RhinoException#

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> = type.resolve(errorReporter, scope); } } /** * Returns whether this variable's type is inferred. To get the variable's * type, see {@link #getType()}. */ public boolean isTypeInferred() { return typeInferred; } public String getInputName() { if (input == null) return "<non-file>"; else return input.getName(); } public boolean isNoShadow() { if (info != null && info.isNoShadow()) { return true; } else { return false; } } @Override public boolean equals(Object other) { if (!(other instanceof Var)) { return false; } Var otherVar = (Var) other; return otherVar.nameNode == nameNode; } @Override public int hashCode() { return nameNode.hashCode(); } @Override public String toString() { return "Scope.Var " + name; } } /** * Creates a Scope given the parent Scope and the root node of the scope. * @param parent The parent Scope. Cannot be null. * @param rootNode Typically the FUNCTION node. */ Scope(Scope parent, Node rootNode) { Preconditions.checkNotNull(parent); Preconditions.checkArgument(rootNode != parent.rootNode); this.parent = parent; this.rootNode = rootNode; JSType nodeType = rootNode.getJSType(); if (nodeType != null && nodeType instanceof FunctionType) { thisType = ((FunctionType) nodeType).getTypeOfThis(); } else { thisType = parent.thisType; } this.isBottom = false; } /** * Creates a global Scope. * @param rootNode Typically the global BLOCK node. */ Scope(Node rootNode, AbstractCompiler compiler) { this.parent = null; this.rootNode = rootNode; thisType = compiler.getTypeRegistry().getNativeObjectType(GLOBAL_THIS); this.isBottom = false; } /** * Creates a empty Scope (bottom of the lattice). * @param rootNode Typically a FUNCTION node or the global BLOCK node. * @param thisType the type of {@code this} in this scope */ Scope

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>(Node rootNode, ObjectType thisType) { this.parent = null; this.rootNode = rootNode; this.thisType = thisType; this.isBottom = true; } /** Whether this is the bottom of the lattice. */ boolean isBottom() { return isBottom; } /** * Gets the container node of the scope. This is typically the FUNCTION * node or the global BLOCK/SCRIPT node. */ public Node getRootNode() { return rootNode; } public Scope getParent() { return parent; } Scope getGlobalScope() { Scope result = this; while (result.getParent() != null) { result = result.getParent(); } return result; } @Override public StaticScope<JSType> getParentScope() { return parent; } /** * Gets the type of {@code this} in the current scope. */ public ObjectType getTypeOfThis() { return thisType; } /** * Declares a variable whose type is inferred. * * @param name name of the variable * @param nameNode the NAME node declaring the variable * @param type the variable's type * @param input the input in which this variable is defined. */ Var declare(String name, Node nameNode, JSType type, CompilerInput input) { return declare(name, nameNode, type, input, true); } /** * Declares a variable. * * @param name name of the variable * @param nameNode the NAME node declaring the variable * @param type the variable's type * @param input the input in which this variable is defined. * @param inferred Whether this variable's type is inferred (as opposed * to declared). */ Var declare(String name, Node nameNode, JSType type, CompilerInput input, boolean inferred) { Preconditions.checkState(name != null && name.length() > 0); // Make sure that it's declared only once Preconditions.checkState(vars.get(name) == null); Var var = new Var(inferred); var.name = name; var.nameNode = nameNode; var.type = type; var.scope = this; var.

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> /** * The All type is the greatest type (top) and is never a subtype of * another except itself or the Unknown type. * @return {@code this.isEquivalentTo(that)} */ @Override public boolean isSubtype(JSType that) { return that.isAllType() || that.isUnknownType(); } @Override public boolean isAllType() { return true; } @Override public boolean matchesStringContext() { // Be lenient. return true; } @Override public boolean matchesObjectContext() { // Be lenient. return true; } @Override public boolean canBeCalled() { return false; } @Override public TernaryValue testForEquality(JSType that) { return UNKNOWN; } @Override public JSType getLeastSupertype(JSType that) { if (that.isUnknownType()) { return registry.getNativeType(JSTypeNative.UNKNOWN_TYPE); } return this; } @Override public JSType getGreatestSubtype(JSType that) { return that; } @Override public String toString() { return "*"; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseAllType(); } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.BOTH; } @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) { return this; } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>/* * Copyright 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.javascript.jscomp.NodeTraversal.Callback; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; /** * A simple pass to ensure that all AST nodes have line numbers, * an that the line numbers are monotonically increasing. * * @author nicksantos@google.com (Nick Santos) */ class LineNumberCheck implements Callback, CompilerPass { static final DiagnosticType MISSING_LINE_INFO = DiagnosticType.error( "JSC_MISSING_LINE_INFO", "No source location information associated with {0}.\n" + "Most likely a Node has been created with settings the source file " + "and line/column location. Usually this is done using " + "Node.copyInformationFrom and supplying a Node from the source AST."); private final AbstractCompiler compiler; private boolean requiresLineNumbers = false; LineNumberCheck(AbstractCompiler compiler) { this.compiler = compiler; } public void setCheckSubTree(Node root) { requiresLineNumbers = true; NodeTraversal.traverse(compiler, root, this); } public void process(Node externs, Node root) { requiresLineNumbers = false; NodeTraversal.traverse(compiler, root, this); } public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) { // Each JavaScript file is rooted in a script node, so we'll only // have line number information inside the script node. if (n.getType() ==

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> Token.SCRIPT) { requiresLineNumbers = true; } return true; } public void visit(NodeTraversal t, Node n, Node parent) { if (n.getType() == Token.SCRIPT) { requiresLineNumbers = false; } else if (requiresLineNumbers) { if (n.getLineno() == -1) { // The tree version of the node is really the best diagnostic // info we have to offer here. compiler.report( t.makeError(n, MISSING_LINE_INFO, n.toStringTree())); } } } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> MAX_UNION_SIZE) { return this; } // Look through the alternates we've got so far, // and check if any of them are duplicates of // one another. Iterator<JSType> it = alternates.iterator(); while (it.hasNext()) { JSType current = it.next(); if (alternate.isUnknownType() || current.isUnknownType()) { if (alternate.isEquivalentTo(current)) { // Alternate is unnecessary. return this; } } else { if (alternate.isSubtype(current)) { // Alternate is unnecessary. return this; } else if (current.isSubtype(alternate)) { // Alternate makes current obsolete it.remove(); } } } alternates.add(alternate); result = null; // invalidate the memoized result } } else { result = null; } return this; } /** * Creates a union. * @return A UnionType if it has two or more alternates, the * only alternate if it has one and otherwise {@code NO_TYPE}. */ JSType build() { if (result == null) { if (isAllType) { result = registry.getNativeType(ALL_TYPE); } else if (isNativeUnknownType) { if (areAllUnknownsChecked) { result = registry.getNativeType(CHECKED_UNKNOWN_TYPE); } else { result = registry.getNativeType(UNKNOWN_TYPE); } } else { int size = alternates.size(); if (size > MAX_UNION_SIZE) { result = registry.getNativeType(UNKNOWN_TYPE); } else { if (size > 1) { result = new UnionType(registry, getAlternateListCopy()); } else if (size == 1) { result = alternates.iterator().next(); } else { result = registry.getNativeType(NO_TYPE); } } } } return result; } private static final Comparator<JSType> typeSorter = new Comparator<JSType>() { @Override public int compare(JSType a, JSType b) { return b.hashCode() - a.hashCode();

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>/* * Copyright 2007 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.jstype.FunctionType; import com.google.javascript.rhino.jstype.JSTypeNative; import com.google.javascript.rhino.jstype.ObjectType; import java.util.Collection; import java.util.List; import java.util.Set; /** * This describes the Closure-specific JavaScript coding conventions. * * * */ public class ClosureCodingConvention extends DefaultCodingConvention { private static final String TYPEDEF_NAME = "goog.typedef"; static final DiagnosticType OBJECTLIT_EXPECTED = DiagnosticType.warning( "JSC_REFLECT_OBJECTLIT_EXPECTED", "Object literal expected as second argument"); /** * Closure's goog.inherits adds a {@code superClass_} property to the * subclass, and a {@code constructor} property. */ @Override public void applySubclassRelationship(FunctionType parentCtor, FunctionType childCtor, SubclassType type) { if (type == SubclassType.INHERITS) { childCtor.defineDeclaredProperty("superClass_", parentCtor.getPrototype(), false); childCtor.getPrototype().defineDeclaredProperty("constructor", childCtor, false); } } /**

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> * {@inheritDoc} * * <p>Understands several different inheritance patterns that occur in * Google code (various uses of {@code inherits} and {@code mixin}). */ @Override public SubclassRelationship getClassesDefinedByCall(Node callNode) { Node callName = callNode.getFirstChild(); SubclassType type = typeofClassDefiningName(callName); if (type != null) { Node subclass = null; Node superclass = callNode.getLastChild(); // There are six possible syntaxes for a class-defining method: // SubClass.inherits(SuperClass) // goog.inherits(SubClass, SuperClass) // goog$inherits(SubClass, SuperClass) // SubClass.mixin(SuperClass.prototype) // goog.mixin(SubClass.prototype, SuperClass.prototype) // goog$mixin(SubClass.prototype, SuperClass.prototype) if (callNode.getChildCount() == 2 && callName.getType() == Token.GETPROP) { // SubClass.inherits(SuperClass) subclass = callName.getFirstChild(); } else if (callNode.getChildCount() == 3) { // goog.inherits(SubClass, SuperClass) subclass = callName.getNext(); } // bail out if either of the side of the "inherits" // isn't a real class name. This prevents us from // doing something weird in cases like: // goog.inherits(MySubClass, cond ? SuperClass1 : BaseClass2) if (subclass != null && subclass.isUnscopedQualifiedName() && superclass.isUnscopedQualifiedName()) { // make sure to strip the prototype off of the nodes // to normalize for goog.mixin return new SubclassRelationship( type, stripPrototype(subclass), stripPrototype(superclass)); } } return null; } /** * Determines whether the given node is a class-defining name, like * "inherits" or "mixin." * @return The type of class-defining name, or null. */ private SubclassType typeofClassDefiningName(Node callName) { // Check if the method name matches one of the class-defining methods. String methodName = null; if (callName

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>.getType() == Token.GETPROP) { methodName = callName.getLastChild().getString(); } else if (callName.getType() == Token.NAME) { String name = callName.getString(); int dollarIndex = name.lastIndexOf('$'); if (dollarIndex != -1) { methodName = name.substring(dollarIndex + 1); } } if (methodName != null) { if (methodName.equals("inherits")) { return SubclassType.INHERITS; } else if (methodName.equals("mixin")) { return SubclassType.MIXIN; } } return null; } @Override public boolean isSuperClassReference(String propertyName) { return "superClass_".equals(propertyName); } /** * Given a qualified name node, strip "prototype" off the end. * * Examples of this transformation: * a.b.c => a.b.c * a.b.c.prototype => a.b.c */ private Node stripPrototype(Node qualifiedName) { if (qualifiedName.getType() == Token.GETPROP && qualifiedName.getLastChild().getString().equals("prototype")) { return qualifiedName.getFirstChild(); } return qualifiedName; } /** * Exctracts X from goog.provide('X'), if the applied Node is goog. * * @return The extracted class name, or null. */ @Override public String extractClassNameIfProvide(Node node, Node parent){ return extractClassNameIfGoog(node, parent, "goog.provide"); } /** * Exctracts X from goog.require('X'), if the applied Node is goog. * * @return The extracted class name, or null. */ @Override public String extractClassNameIfRequire(Node node, Node parent){ return extractClassNameIfGoog(node, parent, "goog.require"); } private static String extractClassNameIfGoog(Node node, Node parent, String functionName){ String className = null; if (NodeUtil.isExprCall(parent)) { Node callee = node.getFirstChild(); if (callee != null && callee.getType() == Token.GETPROP) { String qualifiedName = callee

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>.getQualifiedName(); if ((functionName).equals(qualifiedName)) { className = callee.getNext().getString(); } } } return className; } /** * Use closure's implementation. * @return closure's function name for exporting properties. */ @Override public String getExportPropertyFunction() { return "goog.exportProperty"; } /** * Use closure's implementation. * @return closure's function name for exporting symbols. */ @Override public String getExportSymbolFunction() { return "goog.exportSymbol"; } @Override public List<String> identifyTypeDeclarationCall(Node n) { Node callName = n.getFirstChild(); if ("goog.addDependency".equals(callName.getQualifiedName()) && n.getChildCount() >= 3) { Node typeArray = callName.getNext().getNext(); if (typeArray.getType() == Token.ARRAYLIT) { List<String> typeNames = Lists.newArrayList(); for (Node name = typeArray.getFirstChild(); name != null; name = name.getNext()) { if (name.getType() == Token.STRING) { typeNames.add(name.getString()); } } return typeNames; } } return null; } @Override public String identifyTypeDefAssign(Node n) { Node firstChild = n.getFirstChild(); int type = n.getType(); if (type == Token.ASSIGN) { if (TYPEDEF_NAME.equals(n.getLastChild().getQualifiedName())) { return firstChild.getQualifiedName(); } } else if (type == Token.VAR && firstChild.hasChildren()) { if (TYPEDEF_NAME.equals( firstChild.getFirstChild().getQualifiedName())) { return firstChild.getString(); } } return null; } @Override public String getAbstractMethodName() { return "goog.abstractMethod"; } @Override public String getSingletonGetterClassName(Node callNode) { Node callArg = callNode.getFirstChild(); String callName = callArg.getQualifiedName(); // Use both the original name and the post-CollapseProperties name. if (!("goog.addSingletonGetter".equals(callName) || "goog$add

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>SingletonGetter".equals(callName)) || callNode.getChildCount() != 2) { return null; } return callArg.getNext().getQualifiedName(); } @Override public void applySingletonGetter(FunctionType functionType, FunctionType getterType, ObjectType objectType) { functionType.defineDeclaredProperty("getInstance", getterType, false); functionType.defineDeclaredProperty("instance_", objectType, false); } @Override public String getGlobalObject() { return "goog.global"; } private final Set<String> propertyTestFunctions = ImmutableSet.of( "goog.isDef", "goog.isNull", "goog.isDefAndNotNull", "goog.isString", "goog.isNumber", "goog.isBoolean", "goog.isFunction", "goog.isArray", "goog.isObject"); @Override public boolean isPropertyTestFunction(Node call) { Preconditions.checkArgument(call.getType() == Token.CALL); return propertyTestFunctions.contains( call.getFirstChild().getQualifiedName()); } @Override public ObjectLiteralCast getObjectLiteralCast(NodeTraversal t, Node callNode) { Preconditions.checkArgument(callNode.getType() == Token.CALL); Node callName = callNode.getFirstChild(); if (!"goog.reflect.object".equals(callName.getQualifiedName()) || callName.getChildCount() != 2) { return null; } Node typeNode = callName.getNext(); if (!typeNode.isQualifiedName()) { return null; } Node objectNode = typeNode.getNext(); if (objectNode.getType() != Token.OBJECTLIT) { t.getCompiler().report(JSError.make(t.getSourceName(), callNode, OBJECTLIT_EXPECTED)); return null; } return new ObjectLiteralCast(typeNode.getQualifiedName(), typeNode.getNext()); } @Override public boolean isOptionalParameter(Node parameter) { return false; } @Override public boolean isVarArgsParameter(Node parameter) { return false; } @Override public boolean isPrivate(String name) { return false; } @Override public Collection<AssertionFunctionSpec> getAssertionFunctions() { return ImmutableList.<AssertionFunctionSpec>

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>is_namespace"; case IS_DISPATCHER: return "is_dispatcher"; case DIRECTIVES: return "directives"; case DIRECT_EVAL: return "direct_eval"; default: Kit.codeBug(); } return null; } private static class NumberNode extends Node { private static final long serialVersionUID = 1L; NumberNode(double number) { super(Token.NUMBER); this.number = number; } public NumberNode(double number, int lineno, int charno) { super(Token.NUMBER, lineno, charno); this.number = number; } @Override public double getDouble() { return this.number; } @Override public void setDouble(double d) { this.number = d; } @Override public boolean isEquivalentTo(Node node) { return (node instanceof NumberNode && getDouble() == ((NumberNode) node).getDouble()); } private double number; } private static class StringNode extends Node { private static final long serialVersionUID = 1L; StringNode(int type, String str) { super(type); if (null == str) { throw new IllegalArgumentException("StringNode: str is null"); } this.str = str; } StringNode(int type, String str, int lineno, int charno) { super(type, lineno, charno); if (null == str) { throw new IllegalArgumentException("StringNode: str is null"); } this.str = str; } /** * returns the string content. * @return non null. */ @Override public String getString() { return this.str; } /** * sets the string content. * @param str the new value. Non null. */ @Override public void setString(String str) { if (null == str) { throw new IllegalArgumentException("StringNode: str is null"); } this.str = str; } @Override public boolean isEquivalentTo(Node node) { return (node instanceof StringNode && this.str.equals(((StringNode) node).str)); } /** * If the property is not defined, this was not a quoted key.

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> The * QUOTED_PROP int property is only assigned to STRING tokens used as * object lit keys. * @return true if this was a quoted string key in an object literal. */ @Override public boolean isQuotedString() { return getBooleanProp(QUOTED_PROP); } /** * This should only be called for STRING nodes created in object lits. */ @Override public void setQuotedString() { putBooleanProp(QUOTED_PROP, true); } private String str; } // PropListItems are immutable so that they can be shared. private static class PropListItem implements Serializable { private static final long serialVersionUID = 1L; final PropListItem next; final int type; final int intValue; final Object objectValue; PropListItem(int type, int intValue, PropListItem next) { this(type, intValue, null, next); } PropListItem(int type, Object objectValue, PropListItem next) { this(type, 0, objectValue, next); } PropListItem( int type, int intValue, Object objectValue, PropListItem next) { this.type = type; this.intValue = intValue; this.objectValue = objectValue; this.next = next; } } public Node(int nodeType) { type = nodeType; parent = null; sourcePosition = -1; } public Node(int nodeType, Node child) { Preconditions.checkArgument(child.parent == null, "new child has existing parent"); Preconditions.checkArgument(child.next == null, "new child has existing sibling"); type = nodeType; parent = null; first = last = child; child.next = null; child.parent = this; sourcePosition = -1; } public Node(int nodeType, Node left, Node right) { Preconditions.checkArgument(left.parent == null, "first new child has existing parent"); Preconditions.checkArgument(left.next == null, "first new child has existing sibling"); Preconditions.checkArgument(right.parent == null, "second new child has existing parent"); Preconditions.checkArgument(right.next == null, "second

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> Token.STRING) { throw new IllegalStateException( "String node not created with Node.newString"); } else { throw new UnsupportedOperationException(this + " is not a string node"); } } @Override public String toString() { return toString(true, true, true); } public String toString( boolean printSource, boolean printAnnotations, boolean printType) { if (Token.printTrees) { StringBuilder sb = new StringBuilder(); toString(sb, printSource, printAnnotations, printType); return sb.toString(); } return String.valueOf(type); } private void toString( StringBuilder sb, boolean printSource, boolean printAnnotations, boolean printType) { if (Token.printTrees) { sb.append(Token.name(type)); if (this instanceof StringNode) { sb.append(' '); sb.append(getString()); } else if (type == Token.FUNCTION) { sb.append(' '); // In the case of JsDoc trees, the first child is often not a string // which causes exceptions to be thrown when calling toString or // toStringTree. if (first.getType() == Token.STRING) { sb.append(first.getString()); } } else if (this instanceof ScriptOrFnNode) { ScriptOrFnNode sof = (ScriptOrFnNode) this; if (this instanceof FunctionNode) { FunctionNode fn = (FunctionNode) this; sb.append(' '); sb.append(fn.getFunctionName()); } if (printSource) { sb.append(" [source name: "); sb.append(sof.getSourceName()); sb.append("] [encoded source length: "); sb.append(sof.getEncodedSourceEnd() - sof.getEncodedSourceStart()); sb.append("] [base line: "); sb.append(sof.getBaseLineno()); sb.append("] [end line: "); sb.append(sof.getEndLineno()); sb.append(']'); } } else if (type == Token.NUMBER) { sb.append(' '); sb.append(getDouble()); } if (printSource) { int lineno = getLineno(); if (lineno != -1) {

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> nodes's children. * The iterator does not support the optional operation * {@link Iterator#remove()}.</p> * * <p>To iterate over a node's siblings, one can write</p> * <pre>Node n = ...; * for (Node child : n.children()) { ...</pre> */ public Iterable<Node> children() { if (first == null) { return Collections.emptySet(); } else { return new SiblingNodeIterable(first); } } /** * <p>Return an iterable object that iterates over this nodes's siblings. * The iterator does not support the optional operation * {@link Iterator#remove()}.</p> * * <p>To iterate over a node's siblings, one can write</p> * <pre>Node n = ...; * for (Node sibling : n.siblings()) { ...</pre> */ public Iterable<Node> siblings() { return new SiblingNodeIterable(this); } /** * @see Node#siblings() */ private static final class SiblingNodeIterable implements Iterable<Node>, Iterator<Node> { private final Node start; private Node current; private boolean used; SiblingNodeIterable(Node start) { this.start = start; this.current = start; this.used = false; } public Iterator<Node> iterator() { if (!used) { used = true; return this; } else { // We have already used the current object as an iterator; // we must create a new SiblingNodeIterable based on this // iterable's start node. // // Since the primary use case for Node.children is in for // loops, this branch is extremely unlikely. return (new SiblingNodeIterable(start)).iterator(); } } public boolean hasNext() { return current != null; } public Node next() { if (current == null) { throw new NoSuchElementException(); } try { return current; } finally { current = current.getNext(); } } public void remove() { throw new UnsupportedOperationException(); } } // ========================================================================== // Accessors public Node getParent() { return parent;

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>BREAK: return "break"; case Token.CONTINUE: return "continue"; case Token.VAR: return "var"; case Token.WITH: return "with"; case Token.CATCH: return "catch"; case Token.FINALLY: return "finally"; case Token.RESERVED: return "reserved"; case Token.NOT: return "not"; case Token.VOID: return "void"; case Token.BLOCK: return "block"; case Token.ARRAYLIT: return "arraylit"; case Token.OBJECTLIT: return "objectlit"; case Token.LABEL: return "label"; case Token.TARGET: return "target"; case Token.LOOP: return "loop"; case Token.EXPR_VOID: return "expr_void"; case Token.EXPR_RESULT: return "expr_result"; case Token.JSR: return "jsr"; case Token.SCRIPT: return "script"; case Token.EMPTY: return "empty"; case Token.GET_REF: return "get_ref"; case Token.REF_SPECIAL: return "ref_special"; } return "<unknown="+token+">"; } /** Returns true if this node is equivalent semantically to another */ public boolean isEquivalentTo(Node node) { if (type == Token.ARRAYLIT) { try { int[] indices1 = (int[]) getProp(Node.SKIP_INDEXES_PROP); int[] indices2 = (int[]) node.getProp(Node.SKIP_INDEXES_PROP); if (indices1 == null) { if (indices2 != null) { return false; } } else if (indices2 == null) { return false; } else if (indices1.length != indices2.length) { return false; } else { for (int i = 0; i < indices1.length; i++) { if (indices1[i] != indices2[i]) { return false; } } } } catch (Exception e) { return false; } } else if (type == Token.INC || type == Token.DEC) { int post1 = this.getIntProp(INCRDE

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>); } /** * Returns whether this is a synthetic block that should not be considered * a real source block. */ public boolean wasEmptyNode() { return getBooleanProp(EMPTY_BLOCK); } /** * Marks this function or constructor call node as having no side effects. * This property is only meaningful for {@link Token#CALL} and * {@link Token#NEW} nodes. */ public void setIsNoSideEffectsCall() { Preconditions.checkArgument( getType() == Token.CALL || getType() == Token.NEW, "setIsNoSideEffectsCall only supports CALL and NEW nodes, got " + Token.name(getType())); putBooleanProp(NO_SIDE_EFFECTS_CALL, true); } /** * Returns true if this node is a function or constructor call that * has no side effects. */ public boolean isNoSideEffectsCall() { return getBooleanProp(NO_SIDE_EFFECTS_CALL); } /** * This should only be called for STRING nodes created in object lits. */ public boolean isQuotedString() { return false; } /** * This should only be called for STRING nodes created in object lits. */ public void setQuotedString() { Kit.codeBug(); } static class NodeMismatch { final Node nodeA; final Node nodeB; NodeMismatch(Node nodeA, Node nodeB) { this.nodeA = nodeA; this.nodeB = nodeB; } @Override public boolean equals(Object object) { if (object instanceof NodeMismatch) { NodeMismatch that = (NodeMismatch) object; return that.nodeA.equals(this.nodeA) && that.nodeB.equals(this.nodeB); } return false; } @Override public int hashCode() { return Objects.hashCode(nodeA, nodeB); } } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import static com.google.javascript.rhino.jstype.TernaryValue.FALSE; import static com.google.javascript.rhino.jstype.TernaryValue.UNKNOWN; /** * Number type. * */ public class NumberType extends ValueType { private static final long serialVersionUID = 1L; NumberType(JSTypeRegistry registry) { super(registry); } @

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>Override public boolean isNullable() { return false; } @Override public TernaryValue testForEquality(JSType that) { if (UNKNOWN.equals(super.testForEquality(that))) { return UNKNOWN; } if (that.isUnknownType() || that.isSubtype( getNativeType(JSTypeNative.OBJECT_NUMBER_STRING_BOOLEAN))) { return UNKNOWN; } return FALSE; } @Override public boolean isNumberValueType() { return true; } @Override public boolean matchesNumberContext() { return true; } @Override public boolean matchesStringContext() { return true; } @Override public boolean matchesObjectContext() { // TODO(user): Revisit this for ES4, which is stricter. return true; } @Override public String toString() { return "number"; } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.BOTH; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseNumberType(); } @Override public JSType autoboxesTo() { return getNativeType(JSTypeNative.NUMBER_OBJECT_TYPE); } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>(JSTypeRegistry registry, FunctionType constructor, boolean isNativeType) { super(registry, null, null, isNativeType); Preconditions.checkNotNull(constructor); this.constructor = constructor; } @Override public String getReferenceName() { return getConstructor().getReferenceName(); } @Override public boolean hasReferenceName() { return getConstructor().hasReferenceName(); } @Override public ObjectType getImplicitPrototype() { return getConstructor().getPrototype(); } @Override public FunctionType getConstructor() { return constructor; } @Override boolean defineProperty(String name, JSType type, boolean inferred, boolean inExterns) { ObjectType proto = getImplicitPrototype(); if (proto != null && proto.hasOwnDeclaredProperty(name)) { return false; } return super.defineProperty(name, type, inferred, inExterns); } @Override public String toString() { if (constructor.hasReferenceName()) { return constructor.getReferenceName(); } else { return super.toString(); } } @Override boolean isTheObjectType() { return getConstructor().isNative() && "Object".equals(getReferenceName()); } @Override public boolean isInstanceType() { return true; } @Override public boolean isArrayType() { return getConstructor().isNative() && "Array".equals(getReferenceName()); } @Override public boolean isStringObjectType() { return getConstructor().isNative() && "String".equals(getReferenceName()); } @Override public boolean isBooleanObjectType() { return getConstructor().isNative() && "Boolean".equals(getReferenceName()); } @Override public boolean isNumberObjectType() { return getConstructor().isNative() && "Number".equals(getReferenceName()); } @Override public boolean isDateType() { return getConstructor().isNative() && "Date".equals(getReferenceName()); } @Override public boolean isRegexpType() { return getConstructor().isNative() && "RegExp".equals(getReferenceName()); } @Override public boolean isNominalType() { return hasReferenceName(); } @Override public boolean isEquivalentTo(JSType that) { if (this == that)

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> { return true; } else if (this.isNominalType()) { ObjectType thatObj = ObjectType.cast(that); if (thatObj != null && thatObj.isNominalType()) { return getReferenceName().equals(thatObj.getReferenceName()); } } return false; } /** * If this is equal to a NamedType object, its hashCode must be equal * to the hashCode of the NamedType object. */ @Override public int hashCode() { if (hasReferenceName()) { return getReferenceName().hashCode(); } else { return super.hashCode(); } } @Override public Iterable<ObjectType> getCtorImplementedInterfaces() { return getConstructor().getImplementedInterfaces(); } // The owner will always be a resolved type, so there's no need to set // the constructor in resolveInternal. // (it would lead to infinite loops if we did). // JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope); }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>1L; NullType(JSTypeRegistry registry) { super(registry); } @Override public boolean isNullType() { return true; } @Override public boolean isNullable() { return true; } @Override public boolean matchesNumberContext() { return true; } @Override public boolean matchesObjectContext() { return false; } @Override public boolean matchesStringContext() { return true; } @Override public JSType restrictByNotNullOrUndefined() { return registry.getNativeType(JSTypeNative.NO_TYPE); } @Override public TernaryValue testForEquality(JSType that) { if (UNKNOWN.equals(super.testForEquality(that))) { return UNKNOWN; } if (that.isNullType() || that.isVoidType()) { return TRUE; } if (that.isUnknownType() || that.isNullable()) { return UNKNOWN; } return FALSE; } @Override public String toString() { return "null"; } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.FALSE; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseNullType(); } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>/* * Copyright 2010 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.collect.ImmutableSet; import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; import com.google.javascript.rhino.Node; /** * A compiler pass to run various peephole optimizations (e.g. constant folding, * some useless code removal, some minimizations). * * @author dcc@google.com (Devin Coughlin) */ class PeepholeOptimizationsPass extends AbstractPostOrderCallback implements CompilerPass { private AbstractCompiler compiler; private ImmutableSet<AbstractPeepholeOptimization> peepholeOptimizations; PeepholeOptimizationsPass(AbstractCompiler compiler, ImmutableSet<AbstractPeepholeOptimization> optimizations) { this.compiler = compiler; this.peepholeOptimizations = optimizations; } /** * Creates a peephole optimization pass that runs the given * optimizations. */ PeepholeOptimizationsPass(AbstractCompiler compiler, AbstractPeepholeOptimization... optimizations) { this(compiler, ImmutableSet.copyOf(optimizations)); } public AbstractCompiler getCompiler() { return compiler; } @Override public void process(Node externs, Node root) { NodeTraversal t = new NodeTraversal(compiler, this); beginTraversal(t); t.traverse(root); endTraversal(t); } @Override public void visit(NodeTraversal t, Node n, Node parent) { Node currentVersionOfNode = n; boolean somethingChanged =

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> ownerFunction, ObjectType implicitPrototype, boolean isNative) { super(registry, null /* has no class name */, implicitPrototype, isNative); this.ownerFunction = ownerFunction; } FunctionPrototypeType(JSTypeRegistry registry, FunctionType ownerFunction, ObjectType implicitPrototype) { this(registry, ownerFunction, implicitPrototype, false); } @Override public String getReferenceName() { if (ownerFunction == null) { return "{...}.prototype"; } else { return ownerFunction.getReferenceName() + ".prototype"; } } @Override public boolean hasReferenceName() { return ownerFunction != null && ownerFunction.hasReferenceName(); } @Override public boolean isFunctionPrototypeType() { return true; } public FunctionType getOwnerFunction() { return ownerFunction; } @Override public Iterable<ObjectType> getCtorImplementedInterfaces() { return getOwnerFunction().getImplementedInterfaces(); } // The owner will always be a resolved type, so there's no need to set // the ownerFunction in resolveInternal. // (it would lead to infinite loops if we did). // JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope); }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> = createUnionType(NUMBER_OBJECT_TYPE, NUMBER_TYPE); registerNativeType( JSTypeNative.NUMBER_VALUE_OR_OBJECT_TYPE, NUMBER_VALUE_OR_OBJECT_TYPE); // unknown function type, i.e. (?...) -> ? FunctionType U2U_FUNCTION_TYPE = createFunctionType(UNKNOWN_TYPE, true, UNKNOWN_TYPE); registerNativeType(JSTypeNative.U2U_FUNCTION_TYPE, U2U_FUNCTION_TYPE); // unknown constructor type, i.e. (?...) -> ? with the NoObject type // as instance type FunctionType U2U_CONSTRUCTOR_TYPE = // This is equivalent to // createConstructorType(UNKNOWN_TYPE, true, UNKNOWN_TYPE), but, // in addition, overrides getInstanceType() to return the NoObject type // instead of a new anonymous object. new FunctionType(this, "Function", null, createArrowType( createParametersWithVarArgs(UNKNOWN_TYPE), UNKNOWN_TYPE), NO_OBJECT_TYPE, null, true, true) { private static final long serialVersionUID = 1L; @Override public FunctionType getConstructor() { return registry.getNativeFunctionType( JSTypeNative.FUNCTION_FUNCTION_TYPE); } }; // The U2U_CONSTRUCTOR is weird, because it's the supertype of its // own constructor. registerNativeType(JSTypeNative.U2U_CONSTRUCTOR_TYPE, U2U_CONSTRUCTOR_TYPE); registerNativeType( JSTypeNative.FUNCTION_INSTANCE_TYPE, U2U_CONSTRUCTOR_TYPE); FUNCTION_FUNCTION_TYPE.setInstanceType(U2U_CONSTRUCTOR_TYPE); U2U_CONSTRUCTOR_TYPE.setImplicitPrototype(FUNCTION_PROTOTYPE); // least function type, i.e. (All...) -> NoType FunctionType LEAST_FUNCTION_TYPE = createFunctionType(NO_TYPE, true, ALL_TYPE); registerNativeType(JSTypeNative.LEAST_FUNCTION_TYPE, LEAST_FUNCTION_TYPE); // the 'this' object in the global scope ObjectType GLOBAL_THIS = createObjectType("global this", null, UNKNOWN_TYPE /* to be resolved later */); registerNativeType(JSTypeNative

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> a function is not specified return getNativeType(UNKNOWN_TYPE); case Token.VOID: // Only allowed in the return value of a function. return getNativeType(VOID_TYPE); case Token.STRING: JSType namedType = getType(scope, n.getString(), sourceName, n.getLineno(), n.getCharno()); if (forgiving) { namedType.forgiveUnknownNames(); } if (resolveMode != ResolveMode.LAZY_NAMES) { namedType = namedType.resolveInternal(reporter, scope); } if ((namedType instanceof ObjectType) && !(enumTypeNames.contains(n.getString()))) { Node typeList = n.getFirstChild(); if (typeList != null && ("Array".equals(n.getString()) || "Object".equals(n.getString()))) { JSType parameterType = createFromTypeNodesInternal( typeList.getLastChild(), sourceName, scope, false); namedType = new ParameterizedType( this, (ObjectType) namedType, parameterType); if (typeList.hasMoreThanOneChild()) { JSType indexType = createFromTypeNodesInternal( typeList.getFirstChild(), sourceName, scope, false); namedType = new IndexedType( this, (ObjectType) namedType, indexType); } } return createDefaultObjectUnion(namedType); } else { return namedType; } case Token.FUNCTION: ObjectType thisType = null; Node current = n.getFirstChild(); if (current.getType() == Token.THIS) { Node thisNode = current.getFirstChild(); thisType = ObjectType.cast( createFromTypeNodesInternal( thisNode, sourceName, scope, false) .restrictByNotNullOrUndefined()); if (thisType == null) { reporter.warning( ScriptRuntime.getMessage0("msg.jsdoc.function.thisnotobject"), sourceName, thisNode.getLineno(), "", thisNode.getCharno()); } current = current.getNext(); } FunctionParamBuilder paramBuilder = new FunctionParamBuilder(this); if (current.getType() == Token.LP) { Node args = current.getFirstChild(); for (Node arg = current.getFirst

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> typeA.isEquivalentTo(typeB); } @Override public boolean equals(Object jsType) { return (jsType instanceof JSType) ? isEquivalentTo((JSType) jsType) : false; } @Override public int hashCode() { return System.identityHashCode(this); } /** * This predicate is used to test whether a given type can appear in a * 'Int32' context. This context includes, for example, the operands of a * bitwise or operator. Since we do not currently support integer types, * this is a synonym for {@code Number}. */ public final boolean matchesInt32Context() { return matchesNumberContext(); } /** * This predicate is used to test whether a given type can appear in a * 'Uint32' context. This context includes the right-hand operand of a shift * operator. */ public final boolean matchesUint32Context() { return matchesNumberContext(); } /** * This predicate is used to test whether a given type can appear in a * numeric context, such as an operand of a multiply operator. */ public boolean matchesNumberContext() { return false; } /** * This predicate is used to test whether a given type can appear in a * {@code String} context, such as an operand of a string concat (+) operator. * * All types have at least the potential for converting to {@code String}. * When we add externally defined types, such as a browser OM, we may choose * to add types that do not automatically convert to {@code String}. */ public boolean matchesStringContext() { return false; } /** * This predicate is used to test whether a given type can appear in an * {@code Object} context, such as the expression in a with statement. * * Most types we will encounter, except notably {@code null}, have at least * the potential for converting to {@code Object}. Host defined objects can * get peculiar. */ public boolean matchesObjectContext() { return false; } /** * Coerces this type to an Object type, then gets the type of the property * whose name is given. * * Unlike {@

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>that.isUnknownType()) { return !this.isEquivalentTo(that); } // otherwise, they're different iff one is unknown and the other is not. return this.isUnknownType() ^ that.isUnknownType(); } /** * A generic implementation meant to be used as a helper for common subtyping * cases. */ static boolean isSubtype(JSType thisType, JSType thatType) { // unknown if (thatType.isUnknownType()) { return true; } // equality if (thisType.isEquivalentTo(thatType)) { return true; } // all type if (thatType.isAllType()) { return true; } // unions if (thatType instanceof UnionType) { UnionType union = (UnionType)thatType; for (JSType element : union.alternates) { if (thisType.isSubtype(element)) { return true; } } } // named types if (thatType instanceof NamedType) { return thisType.isSubtype(((NamedType)thatType).referencedType); } return false; } /** * Visit this type with the given visitor. * @see com.google.javascript.rhino.jstype.Visitor * @return the value returned by the visitor */ public abstract <T> T visit(Visitor<T> visitor); /** * Force this type to resolve, even if the registry is in a lazy * resolving mode. * @see #resolve */ public final JSType forceResolve(ErrorReporter t, StaticScope<JSType> scope) { ResolveMode oldResolveMode = registry.getResolveMode(); registry.setResolveMode(ResolveMode.IMMEDIATE); JSType result = resolve(t, scope); registry.setResolveMode(oldResolveMode); return result; } /** * Resolve this type in the given scope. * * The returned value must be equal to {@code this}, as defined by * {@link #isEquivalentTo}. It may or may not be the same object. This method * may modify the internal state of {@code this}, as long as it does * so in a way that preserves Object equality. * * For efficiency,

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> arrow type from the complex * {@link FunctionType} that models JavaScript's notion of functions. * * */ final class ArrowType extends JSType { private static final long serialVersionUID = 1L; final Node parameters; JSType returnType; // Whether the return type is inferred. final boolean returnTypeInferred; ArrowType(JSTypeRegistry registry, Node parameters, JSType returnType) { this(registry, parameters, returnType, false); } ArrowType(JSTypeRegistry registry, Node parameters, JSType returnType, boolean returnTypeInferred) { super(registry); this.parameters = parameters == null ? registry.createParametersWithVarArgs(getNativeType(UNKNOWN_TYPE)) : parameters; this.returnType = returnType == null ? getNativeType(UNKNOWN_TYPE) : returnType; this.returnTypeInferred = returnTypeInferred; } @Override public boolean isSubtype(JSType other) { if (!(other instanceof ArrowType)) { return false; } ArrowType that = (ArrowType) other; // this.returnType <: that.returnType (covariant) if (!this.returnType.isSubtype(that.returnType)) { return false; } // that.paramType[i] <: this.paramType[i] (contravariant) // TODO(nicksantos): This is incorrect. It should be invariant. // Follow up with closure team on how to fix this without everyone // hating on us. Node thisParam = parameters.getFirstChild(); Node thatParam = that.parameters.getFirstChild(); while (thisParam != null && thatParam != null) { JSType thisParamType = thisParam.getJSType(); if (thisParamType != null) { JSType thatParamType = thatParam.getJSType(); if (thatParamType == null || !thatParamType.isSubtype(thisParamType)) { return false; } } boolean thisIsVarArgs = thisParam.isVarArgs(); boolean thatIsVarArgs = thatParam.isVarArgs(); // don't advance if we have variable arguments if (!thisIsVarArgs) { thisParam = thisParam.getNext(); } if (!thatIsVarArgs) { thatParam = that

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>Param.getNext(); } // both var_args indicates the end if (thisIsVarArgs && thatIsVarArgs) { thisParam = null; thatParam = null; } } // Right now, the parser's type system doesn't have a good way // to model optional arguments. // // Suppose we have // function f(number, number) {} // function g(number) {} // If the second arg of f is optional, then f is a subtype of g, // but g is not a subtype of f. // If the second arg of f is required, then g is a subtype of f, // but f is not a subtype of g. // // Until we model optional params, let's just punt on this. // If one type has more arguments than the other, we won't check them. // // NOTE(nicksantos): This is described in Draft 2 of the ES4 spec, // Section 3.4.6: Subtyping Function Types. It seems really // strange but I haven't thought a lot about the implementation. return true; } /** * @return True if our parameter spec is equal to {@code that}'s parameter * spec. */ boolean hasEqualParameters(ArrowType that) { Node thisParam = parameters.getFirstChild(); Node otherParam = that.parameters.getFirstChild(); while (thisParam != null && otherParam != null) { JSType thisParamType = thisParam.getJSType(); JSType otherParamType = otherParam.getJSType(); if (thisParamType != null) { // Both parameter lists give a type for this param, it should be equal if (otherParamType != null && !thisParamType.isEquivalentTo(otherParamType)) { return false; } } else { if (otherParamType != null) { return false; } } thisParam = thisParam.getNext(); otherParam = otherParam.getNext(); } // One of the parameters is null, so the types are only equal if both // parameter lists are null (they are equal). return thisParam == otherParam; } @Override public boolean isEquivalentTo(JSType object) { // Please

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> keep this method in sync with the hashCode() method below. if (!(object instanceof ArrowType)) { return false; } ArrowType that = (ArrowType) object; if (!returnType.isEquivalentTo(that.returnType) || returnTypeInferred != that.returnTypeInferred) { return false; } return hasEqualParameters(that); } @Override public int hashCode() { int hashCode = 0; if (returnType != null) { hashCode += returnType.hashCode(); } if (returnTypeInferred) { hashCode += 1; } if (parameters != null) { Node param = parameters.getFirstChild(); while (param != null) { JSType paramType = param.getJSType(); if (paramType != null) { hashCode += paramType.hashCode(); } param = param.getNext(); } } return hashCode; } @Override public JSType getLeastSupertype(JSType that) { throw new UnsupportedOperationException(); } @Override public JSType getGreatestSubtype(JSType that) { throw new UnsupportedOperationException(); } @Override public TernaryValue testForEquality(JSType that) { throw new UnsupportedOperationException(); } @Override public <T> T visit(Visitor<T> visitor) { throw new UnsupportedOperationException(); } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.TRUE; } @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) { returnType = safeResolve(returnType, t, scope); if (parameters != null) { for (Node paramNode = parameters.getFirstChild(); paramNode != null; paramNode = paramNode.getNext()) { paramNode.setJSType(paramNode.getJSType().resolve(t, scope)); } } return this; } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>ERROR_FUNCTION_TYPE; protected ObjectType TYPE_ERROR_TYPE; protected FunctionType U2U_CONSTRUCTOR_TYPE; protected FunctionType U2U_FUNCTION_TYPE; protected ObjectType UNKNOWN_TYPE; protected JSType URI_ERROR_FUNCTION_TYPE; protected ObjectType URI_ERROR_TYPE; protected JSType VOID_TYPE; protected int NATIVE_PROPERTIES_COUNT; @Override protected void setUp() throws Exception { super.setUp(); errorReporter = new TestErrorReporter(null, null); registry = new JSTypeRegistry(errorReporter); initTypes(); } protected void initTypes() { ALL_TYPE = registry.getNativeType(JSTypeNative.ALL_TYPE); NO_OBJECT_TYPE = registry.getNativeObjectType(JSTypeNative.NO_OBJECT_TYPE); NO_TYPE = registry.getNativeObjectType(JSTypeNative.NO_TYPE); ARRAY_FUNCTION_TYPE = registry.getNativeType(JSTypeNative.ARRAY_FUNCTION_TYPE); ARRAY_TYPE = registry.getNativeObjectType(JSTypeNative.ARRAY_TYPE); BOOLEAN_OBJECT_FUNCTION_TYPE = registry.getNativeType(JSTypeNative.BOOLEAN_OBJECT_FUNCTION_TYPE); BOOLEAN_OBJECT_TYPE = registry.getNativeObjectType(JSTypeNative.BOOLEAN_OBJECT_TYPE); BOOLEAN_TYPE = registry.getNativeType(JSTypeNative.BOOLEAN_TYPE); CHECKED_UNKNOWN_TYPE = registry.getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE); DATE_FUNCTION_TYPE = registry.getNativeType(JSTypeNative.DATE_FUNCTION_TYPE); DATE_TYPE = registry.getNativeObjectType(JSTypeNative.DATE_TYPE); ERROR_FUNCTION_TYPE = registry.getNativeType(JSTypeNative.ERROR_FUNCTION_TYPE); ERROR_TYPE = registry.getNativeObjectType(JSTypeNative.ERROR_TYPE); EVAL_ERROR_FUNCTION_TYPE = registry.getNativeType(JSTypeNative.EVAL_ERROR_FUNCTION_TYPE); EVAL_ERROR_TYPE = registry.getNativeObjectType(JSTypeNative.EVAL_ERROR_TYPE); FUNCTION_FUNCTION_TYPE = registry.getNativeFunctionType(JSTypeNative.FUNCTION_FUNCTION_

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> PassFactory factory, String passName) { factoryList.add( findPassIndexByName(factoryList, passName), factory); } /** * Find a pass factory with the same name as the given one, and replace it. */ final static void replacePassFactory( List<PassFactory> factoryList, PassFactory factory) { factoryList.set( findPassIndexByName(factoryList, factory.getName()), factory); } /** * Throws an exception if no pass with the given name exists. */ private static int findPassIndexByName( List<PassFactory> factoryList, String name) { for (int i = 0; i < factoryList.size(); i++) { if (factoryList.get(i).getName().equals(name)) { return i; } } throw new IllegalArgumentException( "No factory named '" + name + "' in the factory list"); } /** * Find the first pass provider that does not have a delegate. */ final PassConfig getBasePassConfig() { PassConfig current = this; while (current instanceof PassConfigDelegate) { current = ((PassConfigDelegate) current).delegate; } return current; } /** * Get intermediate state for a running pass config, so it can * be paused and started again later. */ abstract State getIntermediateState(); /** * Set the intermediate state for a pass config, to restart * a compilation process that had been previously paused. */ abstract void setIntermediateState(State state); /** * An implementation of PassConfig that just proxies all its method calls * into an inner class. */ static class PassConfigDelegate extends PassConfig { private final PassConfig delegate; PassConfigDelegate(PassConfig delegate) { super(delegate.options); this.delegate = delegate; } @Override protected List<PassFactory> getChecks() { return delegate.getChecks(); } @Override protected List<PassFactory> getOptimizations() { return delegate.getOptimizations(); } @Override ScopeCreator getScopeCreator() { return delegate.getScopeCreator(); } @Override Scope getTopScope() { return delegate.getTopScope(); } @Override State getIntermediateState() { return delegate.get

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>IntermediateState(); } @Override void setIntermediateState(State state) { delegate.setIntermediateState(state); } } /** * Intermediate state for a running pass configuration. */ static class State implements Serializable { private static final long serialVersionUID = 1L; final Map<String, Integer> cssNames; final Set<String> exportedNames; final CrossModuleMethodMotion.IdGenerator crossModuleIdGenerator; final VariableMap variableMap; final VariableMap propertyMap; final VariableMap anonymousFunctionNameMap; final VariableMap stringMap; final FunctionNames functionNames; State(Map<String, Integer> cssNames, Set<String> exportedNames, CrossModuleMethodMotion.IdGenerator crossModuleIdGenerator, VariableMap variableMap, VariableMap propertyMap, VariableMap anonymousFunctionNameMap, VariableMap stringMap, FunctionNames functionNames) { this.cssNames = cssNames; this.exportedNames = exportedNames; this.crossModuleIdGenerator = crossModuleIdGenerator; this.variableMap = variableMap; this.propertyMap = propertyMap; this.anonymousFunctionNameMap = anonymousFunctionNameMap; this.stringMap = stringMap; this.functionNames = functionNames; } } }

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> arrowType, ObjectType typeOfThis, String templateTypeName, boolean isConstructor, boolean nativeType) { super(registry, name, registry.getNativeObjectType(JSTypeNative.FUNCTION_INSTANCE_TYPE), nativeType); Preconditions.checkArgument(source == null || Token.FUNCTION == source.getType()); Preconditions.checkNotNull(arrowType); this.source = source; this.kind = isConstructor ? Kind.CONSTRUCTOR : Kind.ORDINARY; if (isConstructor) { this.typeOfThis = typeOfThis != null && typeOfThis.isNoObjectType() ? typeOfThis : new InstanceObjectType(registry, this, nativeType); } else { this.typeOfThis = typeOfThis != null ? typeOfThis : registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE); } this.call = arrowType; this.templateTypeName = templateTypeName; } /** Creates an instance for a function that is an interface. */ private FunctionType(JSTypeRegistry registry, String name, Node source) { super(registry, name, registry.getNativeObjectType(JSTypeNative.FUNCTION_INSTANCE_TYPE)); Preconditions.checkArgument(source == null || Token.FUNCTION == source.getType()); Preconditions.checkArgument(name != null); this.source = source; this.call = new ArrowType(registry, new Node(Token.LP), null); this.kind = Kind.INTERFACE; this.typeOfThis = new InstanceObjectType(registry, this); } /** Creates an instance for a function that is an interface. */ static FunctionType forInterface( JSTypeRegistry registry, String name, Node source) { return new FunctionType(registry, name, source); } @Override public boolean isInstanceType() { // The universal constructor is its own instance, bizarrely. return isEquivalentTo(registry.getNativeType(U2U_CONSTRUCTOR_TYPE)); } @Override public boolean isConstructor() { return kind == Kind.CONSTRUCTOR; } @Override public boolean isInterface() { return kind == Kind.INTERFACE; } @Override public boolean isOrdinaryFunction() { return kind == Kind.ORDINARY; } @Override public boolean isFunctionType()

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> { return true; } @Override public boolean canBeCalled() { return true; } public Iterable<Node> getParameters() { Node n = getParametersNode(); if (n != null) { return n.children(); } else { return Collections.emptySet(); } } /** Gets an LP node that contains all params. May be null. */ public Node getParametersNode() { return call.parameters; } /** Gets the minimum number of arguments that this function requires. */ public int getMinArguments() { // NOTE(nicksantos): There are some native functions that have optional // parameters before required parameters. This algorithm finds the position // of the last required parameter. int i = 0; int min = 0; for (Node n : getParameters()) { i++; if (!n.isOptionalArg() && !n.isVarArgs()) { min = i; } } return min; } /** * Gets the maximum number of arguments that this function requires, * or Integer.MAX_VALUE if this is a variable argument function. */ public int getMaxArguments() { Node params = getParametersNode(); if (params != null) { Node lastParam = params.getLastChild(); if (lastParam == null || !lastParam.isVarArgs()) { return params.getChildCount(); } } return Integer.MAX_VALUE; } public JSType getReturnType() { return call.returnType; } public boolean isReturnTypeInferred() { return call.returnTypeInferred; } /** Gets the internal arrow type. For use by subclasses only. */ ArrowType getInternalArrowType() { return call; } /** * Gets the {@code prototype} property of this function type. This is * equivalent to {@code (ObjectType) getPropertyType("prototype")}. */ public FunctionPrototypeType getPrototype() { // lazy initialization of the prototype field if (prototype == null) { setPrototype(new FunctionPrototypeType(registry, this, null)); } return prototype; } /** * Sets the prototype, creating the prototype object from the given * base type. * @param baseType The base type. */ public void

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>ObjectType type : implementedInterfaces) { registry.registerTypeImplementingInterface(this, type); } this.implementedInterfaces = ImmutableList.copyOf(implementedInterfaces); } @Override public boolean hasProperty(String name) { return super.hasProperty(name) || "prototype".equals(name); } @Override public boolean hasOwnProperty(String name) { return super.hasOwnProperty(name) || "prototype".equals(name); } @Override public JSType getPropertyType(String name) { if ("prototype".equals(name)) { return getPrototype(); } else { if (!hasOwnProperty(name)) { if ("call".equals(name)) { // Define the "call" function lazily. Node params = getParametersNode(); if (params == null) { // If there's no params array, don't do any type-checking // in this CALL function. defineDeclaredProperty(name, new FunctionBuilder(registry) .withReturnType(getReturnType()) .build(), false); } else { params = params.cloneTree(); Node thisTypeNode = Node.newString(Token.NAME, "thisType"); thisTypeNode.setJSType( registry.createOptionalNullableType(getTypeOfThis())); params.addChildToFront(thisTypeNode); thisTypeNode.setOptionalArg(true); defineDeclaredProperty(name, new FunctionBuilder(registry) .withParamsNode(params) .withReturnType(getReturnType()) .build(), false); } } else if ("apply".equals(name)) { // Define the "apply" function lazily. FunctionParamBuilder builder = new FunctionParamBuilder(registry); // Ecma-262 says that apply's second argument must be an Array // or an arguments object. We don't model the arguments object, // so let's just be forgiving for now. // TODO(nicksantos): Model the Arguments object. builder.addOptionalParams( registry.createNullableType(getTypeOfThis()), registry.createNullableType( registry.getNativeType(JSTypeNative.OBJECT_TYPE))); defineDeclaredProperty(name, new FunctionBuilder(registry) .withParams(builder) .withReturnType(getReturnType

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>()) .build(), false); } } return super.getPropertyType(name); } } @Override boolean defineProperty(String name, JSType type, boolean inferred, boolean inExterns) { if ("prototype".equals(name)) { ObjectType objType = type.toObjectType(); if (objType != null) { if (objType.isEquivalentTo(prototype)) { return true; } return setPrototype( new FunctionPrototypeType( registry, this, objType, isNativeObjectType())); } else { return false; } } return super.defineProperty(name, type, inferred, inExterns); } @Override public boolean isPropertyTypeInferred(String property) { return "prototype".equals(property) || super.isPropertyTypeInferred(property); } @Override public JSType getLeastSupertype(JSType that) { return supAndInfHelper(that, true); } @Override public JSType getGreatestSubtype(JSType that) { return supAndInfHelper(that, false); } private JSType supAndInfHelper(JSType that, boolean leastSuper) { // NOTE(nicksantos): When we remove the unknown type, the function types // form a lattice with the universal constructor at the top of the lattice, // and the NoObject type at the bottom of the lattice. // // When we introduce the unknown type, it's much more difficult to make // heads or tails of the partial ordering of types, because there's no // clear hierarchy between the different components (parameter types and // return types) in the ArrowType. // // Rather than make the situation more complicated by introducing new // types (like unions of functions), we just fallback on the simpler // approach of using the universal constructor and the AnyObject as // the supremum and infinum of all function types. if (isFunctionType() && that.isFunctionType()) { if (isEquivalentTo(that)) { return this; } // If this is a normal function, look to see if the arguments are equal. // If they are, we can just take the least supertype (or greatest // subtype) of the return types. if

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> or someone defines // a bad type. Otherwise the loop should always end. FunctionType ctor = this; while (true) { ObjectType maybeSuperInstanceType = ctor.getPrototype().getImplicitPrototype(); if (maybeSuperInstanceType == null) { return false; } if (maybeSuperInstanceType.isUnknownType()) { return true; } ctor = maybeSuperInstanceType.getConstructor(); if (ctor == null) { return false; } Preconditions.checkState(ctor.isConstructor() || ctor.isInterface()); } } /** * Given a constructor or an interface type and a property, finds the * top-most superclass that has the property defined (including this * constructor). */ public JSType getTopMostDefiningType(String propertyName) { Preconditions.checkState(isConstructor() || isInterface()); Preconditions.checkArgument(getPrototype().hasProperty(propertyName)); FunctionType ctor = this; JSType topInstanceType; do { topInstanceType = ctor.getInstanceType(); ctor = ctor.getSuperClassConstructor(); } while (ctor != null && ctor.getPrototype().hasProperty(propertyName)); return topInstanceType; } /** * Two function types are equal if their signatures match. Since they don't * have signatures, two interfaces are equal if their names match. */ @Override public boolean isEquivalentTo(JSType otherType) { if (!(otherType instanceof FunctionType)) { return false; } FunctionType that = (FunctionType) otherType; if (!that.isFunctionType()) { return false; } if (this.isConstructor()) { if (that.isConstructor()) { return this == that; } return false; } if (this.isInterface()) { if (that.isInterface()) { return this.getReferenceName().equals(that.getReferenceName()); } return false; } if (that.isInterface()) { return false; } return this.typeOfThis.isEquivalentTo(that.typeOfThis) && this.call.isEquivalentTo(that.call); } @Override public int hashCode() { return isInterface() ? getReferenceName().hashCode() : call.hashCode();

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> } public boolean hasEqualCallType(FunctionType otherType) { return this.call.isEquivalentTo(otherType.call); } /** * Informally, a function is represented by * {@code function (params): returnType} where the {@code params} is a comma * separated list of types, the first one being a special * {@code this:T} if the function expects a known type for {@code this}. */ @Override public String toString() { if (this == registry.getNativeType(JSTypeNative.FUNCTION_INSTANCE_TYPE)) { return "Function"; } StringBuilder b = new StringBuilder(32); b.append("function ("); int paramNum = call.parameters.getChildCount(); boolean hasKnownTypeOfThis = !typeOfThis.isUnknownType(); if (hasKnownTypeOfThis) { b.append("this:"); b.append(typeOfThis.toString()); } if (paramNum > 0) { if (hasKnownTypeOfThis) { b.append(", "); } Node p = call.parameters.getFirstChild(); if (p.isVarArgs()) { appendVarArgsString(b, p.getJSType()); } else { b.append(p.getJSType().toString()); } p = p.getNext(); while (p != null) { b.append(", "); if (p.isVarArgs()) { appendVarArgsString(b, p.getJSType()); } else { b.append(p.getJSType().toString()); } p = p.getNext(); } } b.append("): "); b.append(call.returnType); return b.toString(); } /** Gets the string representation of a var args param. */ private void appendVarArgsString(StringBuilder builder, JSType paramType) { if (paramType.isUnionType()) { // Remove the optionalness from the var arg. paramType = ((UnionType) paramType).getRestrictedUnion( registry.getNativeType(JSTypeNative.VOID_TYPE)); } builder.append("...[").append(paramType.toString()).append("]"); } /** * A function is a subtype of another if their call

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> methods are related via * subtyping and {@code this} is a subtype of {@code that} with regard to * the prototype chain. */ @Override public boolean isSubtype(JSType that) { if (this.isEquivalentTo(that)) { return true; } if (that.isFunctionType()) { if (((FunctionType) that).isInterface()) { // Any function can be assigned to an interface function. return true; } if (this.isInterface()) { // An interface function cannot be assigned to anything. return false; } // If functionA is a subtype of functionB, then their "this" types // should be contravariant. However, this causes problems because // of the way we enforce overrides. Because function(this:SubFoo) // is not a subtype of function(this:Foo), our override check treats // this as an error. It also screws up out standard method // for aliasing constructors. Let's punt on all this for now. // TODO(nicksantos): fix this. FunctionType other = (FunctionType) that; return (this.isConstructor() || other.isConstructor() || other.typeOfThis.isSubtype(this.typeOfThis) || this.typeOfThis.isSubtype(other.typeOfThis)) && this.call.isSubtype(other.call); } if (that instanceof UnionType) { UnionType union = (UnionType) that; for (JSType element : union.alternates) { if (this.isSubtype(element)) { return true; } } } return getNativeType(JSTypeNative.FUNCTION_PROTOTYPE).isSubtype(that); } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseFunctionType(this); } /** * Gets the type of instance of this function. * @throws IllegalStateException if this function is not a constructor * (see {@link #isConstructor()}). */ public ObjectType getInstanceType() { Preconditions.checkState(hasInstanceType()); return typeOfThis; } /** Sets the instance type. This should only be used for special native types. */ void setInstanceType(ObjectType instanceType

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS>) { typeOfThis = instanceType; } /** * Returns whether this function type has an instance type. */ public boolean hasInstanceType() { return isConstructor() || isInterface(); } /** * Gets the type of {@code this} in this function. */ public ObjectType getTypeOfThis() { return typeOfThis.isNoObjectType() ? registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE) : typeOfThis; } /** * Gets the source node or null if this is an unknown function. */ public Node getSource() { return source; } /** * Sets the source node. */ public void setSource(Node source) { this.source = source; } /** Adds a type to the list of subtypes for this type. */ private void addSubType(FunctionType subType) { if (subTypes == null) { subTypes = Lists.newArrayList(); } subTypes.add(subType); } /** * Returns a list of types that are subtypes of this type. This is only valid * for constructor functions, and may be null. This allows a downward * traversal of the subtype graph. */ public List<FunctionType> getSubTypes() { return subTypes; } @Override public boolean hasCachedValues() { return prototype != null || super.hasCachedValues(); } /** * Gets the template type name. */ public String getTemplateTypeName() { return templateTypeName; } @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) { setResolvedTypeInternal(this); call = (ArrowType) safeResolve(call, t, scope); prototype = (FunctionPrototypeType) safeResolve(prototype, t, scope); typeOfThis = (ObjectType) safeResolve(typeOfThis, t, scope); boolean changed = false; ImmutableList.Builder<ObjectType> resolvedInterfaces = ImmutableList.builder(); for (ObjectType iface : implementedInterfaces) { ObjectType resolvedIface = (ObjectType) iface.resolve(t, scope); resolvedInterfaces.add(resolvedIface); changed |= (resolvedIface != iface); } if (changed) { implementedInterfaces = resolvedInterfaces.build(); } if

Closure, 148

<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB> } String typeNameString = null; switch (argumentNode.getType()) { case Token.STRING: typeNameString = "string"; break; case Token.NUMBER: typeNameString = "number"; break; case Token.TRUE: case Token.FALSE: typeNameString = "boolean"; break; case Token.NULL: case Token.OBJECTLIT: case Token.ARRAYLIT: typeNameString = "object"; break; <CHANGES> <CHANGEE> case Token.NAME: // We assume here that programs don't change the value of the // keyword undefined to something other than the value undefined. if ("undefined".equals(argumentNode.getString())) { typeNameString = "undefined"; } break; } if (typeNameString != null) { Node newNode = Node.newString(typeNameString); originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode); reportCodeChange(); <FILEE> <FILEB> import com.google.common.collect.Lists; import com.google.javascript.rhino.Node; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; /** * Collects information mapping the generated (compiled) source back to * its original source for debugging purposes. * * @see CodeConsumer * @see CodeGenerator * @see CodePrinter * * * @author johnlenz@google.com (John Lenz) */ public class SourceMap { <CHANGES> <CHANGEE> /** * A mapping from a given position in an input source file to a given position * in the generated code. */ static class Mapping { /** * A unique ID for this mapping for record keeping purposes. */ <CHANGES> int id; <CHANGEE> /** * The input source file. */ String sourceFile; /** * The position of the code in the input source file. Both * the line number and the character index are indexed by * 1 for legacy reasons via the Rhino Node class. */ Position originalPosition; /** * The starting position of the code in the generated source * file which this mapping represents. Indexed by 0. */ Position startPosition; /** * The<SCANS> (subTypes != null) { for (int i = 0; i < subTypes.size(); i++) { subTypes.set(i, (FunctionType) subTypes.get(i).resolve(t, scope)); } } return super.resolveInternal(t, scope); } @Override public String toDebugHashCodeString() { if (this == registry.getNativeType(JSTypeNative.FUNCTION_INSTANCE_TYPE)) { return super.toDebugHashCodeString(); } StringBuilder b = new StringBuilder(32); b.append("function ("); int paramNum = call.parameters.getChildCount(); boolean hasKnownTypeOfThis = !typeOfThis.isUnknownType(); if (hasKnownTypeOfThis) { b.append("this:"); b.append(getDebugHashCodeStringOf(typeOfThis)); } if (paramNum > 0) { if (hasKnownTypeOfThis) { b.append(", "); } Node p = call.parameters.getFirstChild(); b.append(getDebugHashCodeStringOf(p.getJSType())); p = p.getNext(); while (p != null) { b.append(", "); b.append(getDebugHashCodeStringOf(p.getJSType())); p = p.getNext(); } } b.append(")"); b.append(": "); b.append(getDebugHashCodeStringOf(call.returnType)); return b.toString(); } private String getDebugHashCodeStringOf(JSType type) { if (type == this) { return "me"; } else { return type.toDebugHashCodeString(); } } }